From 6acd07cda742cd06de986e60399d776c1d3a6cd9 Mon Sep 17 00:00:00 2001 From: Luke Walton Date: Tue, 2 Jan 2024 14:03:25 +0000 Subject: [PATCH] Add all changes from v1.0.0 internal (#2) --- CHANGELOG.md | 6 + LICENSE-3RD-PARTY | 1 + README.md | 8 +- all_lint_rules.yaml | 223 - analysis_options.yaml | 46 +- doc/assets/calendar.png | Bin 0 -> 7874 bytes doc/assets/chat.png | Bin 0 -> 21800 bytes doc/assets/clock.png | Bin 0 -> 10389 bytes doc/assets/cloud_fail.png | Bin 0 -> 5522 bytes doc/assets/completed_tasks.png | Bin 0 -> 6345 bytes doc/assets/connection_loss.png | Bin 0 -> 6636 bytes doc/assets/dark_mode.png | Bin 0 -> 3350 bytes doc/assets/empty_box.png | Bin 0 -> 3898 bytes doc/assets/internet_fail.png | Bin 0 -> 6234 bytes doc/assets/light_mode.png | Bin 0 -> 5173 bytes doc/assets/load_fail.png | Bin 0 -> 5001 bytes doc/assets/map.png | Bin 0 -> 10887 bytes doc/assets/notes.png | Bin 0 -> 29758 bytes doc/assets/notifications.png | Bin 0 -> 20598 bytes doc/assets/sad_zebra.png | Bin 0 -> 8577 bytes doc/assets/search.png | Bin 0 -> 5425 bytes doc/assets/server_fail.png | Bin 0 -> 5212 bytes doc/assets/sleeping_zebra.png | Bin 0 -> 42015 bytes doc/assets/system_mode.png | Bin 0 -> 3352 bytes {assets => doc/assets}/zds-dark.png | Bin {assets => doc/assets}/zds-light.png | Bin example/.gitignore | 47 + example/.metadata | 44 +- example/android/.gitignore | 2 +- example/android/build.gradle | 4 +- example/assets/colors.json | 19 + example/example.md | 27 + example/ios/Podfile.lock | 93 +- example/ios/Runner.xcodeproj/project.pbxproj | 3 +- .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../xcshareddata/WorkspaceSettings.xcsettings | 8 - example/lib/home.dart | 135 +- example/lib/main.dart | 60 +- example/lib/pages/assets/icons.dart | 48 +- example/lib/pages/assets/images.dart | 80 +- example/lib/pages/components/app_bar.dart | 112 +- .../pages/components/big_toggle_button.dart | 2 +- example/lib/pages/components/block_table.dart | 1 + example/lib/pages/components/bottom_bar.dart | 1 + .../lib/pages/components/bottom_sheet.dart | 174 +- .../lib/pages/components/bottom_tab_bar.dart | 36 +- example/lib/pages/components/button.dart | 80 +- example/lib/pages/components/calendar.dart | 24 +- example/lib/pages/components/card.dart | 10 +- .../lib/pages/components/card_actions.dart | 16 +- example/lib/pages/components/date_picker.dart | 47 +- .../lib/pages/components/default_flutter.dart | 200 + example/lib/pages/components/empty_view.dart | 1 + example/lib/pages/components/expandable.dart | 14 +- .../lib/pages/components/expansion_tile.dart | 381 +- example/lib/pages/components/file_picker.dart | 18 +- example/lib/pages/components/html_view.dart | 731 ++++ .../pages/components/icon_text_button.dart | 6 +- .../lib/pages/components/image_picker.dart | 1 + example/lib/pages/components/index.dart | 5 +- .../lib/pages/components/infinite_list.dart | 1 + .../lib/pages/components/information_bar.dart | 10 +- example/lib/pages/components/list_tile.dart | 584 ++- .../pages/components/list_tile_wrapper.dart | 29 + example/lib/pages/components/modal.dart | 1 + example/lib/pages/components/popover.dart | 14 +- example/lib/pages/components/profile.dart | 2 +- .../lib/pages/components/properties_list.dart | 1 + .../pages/components/quill_editor_demo.dart | 57 + example/lib/pages/components/radio_list.dart | 15 + example/lib/pages/components/search.dart | 12 +- .../lib/pages/components/shake_example.dart | 1 + .../lib/pages/components/sheet_header.dart | 10 +- .../pages/components/slidable_list_tile.dart | 63 +- .../lib/pages/components/split_navigator.dart | 1 + example/lib/pages/components/stats_card.dart | 116 +- example/lib/pages/components/tab_bar.dart | 90 +- example/lib/pages/components/tag.dart | 363 +- example/lib/pages/components/tag_list.dart | 1 + example/lib/pages/components/text_field.dart | 18 +- example/lib/pages/components/toast.dart | 116 +- example/lib/pages/components/toolbar.dart | 36 +- .../lib/pages/components/vertical_nav.dart | 12 +- example/lib/pages/html_view.dart | 782 ++++ example/lib/pages/quill_editor_demo.dart | 80 + example/lib/pages/theme/colors.dart | 220 +- example/lib/pages/theme/text.dart | 37 +- example/lib/pages/utils/color_utils.dart | 2 +- .../lib/pages/utils/theme_color_switch.dart | 69 + .../pages/utils/theme_constrast_switch.dart | 56 + .../lib/pages/utils/theme_mode_switch.dart | 60 + example/lib/routes.dart | 50 +- .../flutter/generated_plugin_registrant.cc | 4 + example/linux/flutter/generated_plugins.cmake | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 16 +- example/macos/Podfile | 2 +- example/macos/Podfile.lock | 53 +- .../macos/Runner.xcodeproj/project.pbxproj | 19 +- example/pubspec.yaml | 16 +- example/web/index.html | 6 +- .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + lib/assets/fonts/selection.json | 3654 +++++++++++------ lib/assets/fonts/zds.ttf | Bin 52296 -> 52624 bytes lib/assets/images/chat.svg | 35 +- lib/assets/images/clock.svg | 1 + lib/assets/images/connection_loss.svg | 1 + lib/assets/images/dark_mode.svg | 1 + lib/assets/images/internet_fail.svg | 1 + lib/assets/images/light_mode.svg | 1 + lib/assets/images/map.svg | 9 +- lib/assets/images/punch.svg | 7 - lib/assets/images/sleeping_zebra.svg | 66 +- lib/assets/images/system_mode.svg | 1 + lib/assets/js/quill.min.js | 8 + lib/assets/strings/ar.json | 8 +- lib/assets/strings/bg.json | 8 +- lib/assets/strings/bs.json | 6 +- lib/assets/strings/cs.json | 8 +- lib/assets/strings/da.json | 6 +- lib/assets/strings/de.json | 6 +- lib/assets/strings/de_AT.json | 6 +- lib/assets/strings/de_BE.json | 6 +- lib/assets/strings/de_CH.json | 6 +- lib/assets/strings/el.json | 6 +- lib/assets/strings/en.json | 6 +- lib/assets/strings/en_CA.json | 6 +- lib/assets/strings/en_GB.json | 6 +- lib/assets/strings/es.json | 8 +- lib/assets/strings/es_CL.json | 8 +- lib/assets/strings/es_EC.json | 8 +- lib/assets/strings/es_ES.json | 8 +- lib/assets/strings/es_MX.json | 142 + lib/assets/strings/es_PE.json | 8 +- lib/assets/strings/es_PR.json | 8 +- lib/assets/strings/es_UY.json | 8 +- lib/assets/strings/fi.json | 6 +- lib/assets/strings/fr.json | 8 +- lib/assets/strings/fr_BE.json | 8 +- lib/assets/strings/fr_CA.json | 8 +- lib/assets/strings/fr_CH.json | 8 +- lib/assets/strings/hr.json | 8 +- lib/assets/strings/hu.json | 6 +- lib/assets/strings/in.json | 8 +- lib/assets/strings/it.json | 8 +- lib/assets/strings/ja.json | 6 +- lib/assets/strings/ka.json | 8 +- lib/assets/strings/ko.json | 6 +- lib/assets/strings/lt.json | 8 +- lib/assets/strings/lv.json | 6 +- lib/assets/strings/mk.json | 6 +- lib/assets/strings/nb.json | 6 +- lib/assets/strings/nl.json | 6 +- lib/assets/strings/pl.json | 6 +- lib/assets/strings/pt.json | 6 +- lib/assets/strings/pt_BR.json | 6 +- lib/assets/strings/ro.json | 6 +- lib/assets/strings/ru.json | 8 +- lib/assets/strings/sk.json | 8 +- lib/assets/strings/sl.json | 8 +- lib/assets/strings/sq.json | 6 +- lib/assets/strings/sr.json | 6 +- lib/assets/strings/sv.json | 6 +- lib/assets/strings/th.json | 6 +- lib/assets/strings/tl.json | 6 +- lib/assets/strings/tr.json | 6 +- lib/assets/strings/uk.json | 8 +- lib/assets/strings/vi.json | 6 +- lib/assets/strings/zh.json | 6 +- lib/assets/strings/zh_HK.json | 6 +- lib/src/components/atoms.dart | 3 + lib/src/components/atoms/absorb_pointer.dart | 5 +- lib/src/components/atoms/avatar.dart | 52 +- lib/src/components/atoms/back_button.dart | 8 +- lib/src/components/atoms/border_clipper.dart | 68 + lib/src/components/atoms/button.dart | 422 +- lib/src/components/atoms/card.dart | 136 +- .../components/atoms/conditional_wrapper.dart | 45 + lib/src/components/atoms/dashed_line.dart | 98 +- lib/src/components/atoms/expandable.dart | 68 +- .../atoms/floating_action_button.dart | 44 +- .../components/atoms/icon_text_button.dart | 67 +- lib/src/components/atoms/index.dart | 24 +- lib/src/components/atoms/label.dart | 24 +- lib/src/components/atoms/notification.dart | 28 +- lib/src/components/atoms/popover.dart | 60 +- lib/src/components/atoms/selection_pills.dart | 183 +- lib/src/components/atoms/shake_animation.dart | 6 +- lib/src/components/atoms/slidable_widget.dart | 95 +- lib/src/components/atoms/tab.dart | 48 +- lib/src/components/atoms/toggle_button.dart | 58 +- .../components/atoms/unread_badge_widget.dart | 52 +- lib/src/components/molecules/block_table.dart | 216 +- .../components/molecules/bottom_sheet.dart | 100 +- .../components/molecules/card_actions.dart | 49 +- lib/src/components/molecules/card_header.dart | 30 +- .../components/molecules/check_button.dart | 106 +- .../molecules/date_range_picker.dart | 366 +- .../molecules/date_time_picker.dart | 199 +- lib/src/components/molecules/dropdown.dart | 94 +- lib/src/components/molecules/empty.dart | 17 +- .../components/molecules/expansion_tile.dart | 173 +- .../molecules/fields_list_tile.dart | 96 +- .../molecules/icon_badge_widget.dart | 54 +- .../components/molecules/information_bar.dart | 105 +- .../components/molecules/input_dialog.dart | 183 +- lib/src/components/molecules/list.dart | 39 +- .../molecules/list_tile_wrapper.dart | 224 +- lib/src/components/molecules/menu.dart | 22 +- lib/src/components/molecules/menu_item.dart | 21 +- .../components/molecules/network_avatar.dart | 75 +- .../molecules/resizeable_text_area.dart | 190 +- .../molecules/responsive_tab_bar.dart | 52 +- lib/src/components/molecules/search.dart | 99 +- .../molecules/selectable_list_tile.dart | 93 +- .../components/molecules/sheet_header.dart | 50 +- .../components/molecules/slidable_button.dart | 382 +- .../molecules/slidable_list_tile.dart | 112 +- lib/src/components/molecules/stats_card.dart | 100 +- lib/src/components/molecules/tab_bar.dart | 214 +- lib/src/components/molecules/tag.dart | 148 +- lib/src/components/molecules/toast.dart | 122 +- lib/src/components/molecules/toolbar.dart | 60 +- .../components/molecules/vertical_nav.dart | 111 +- lib/src/components/organisms.dart | 3 +- lib/src/components/organisms/app_bar.dart | 117 +- lib/src/components/organisms/bottom_bar.dart | 30 +- .../components/organisms/bottom_tab_bar.dart | 103 +- lib/src/components/organisms/calendar.dart | 457 ++- lib/src/components/organisms/date_range.dart | 150 +- .../organisms/date_range_picker_tile.dart | 459 ++- lib/src/components/organisms/day_picker.dart | 111 +- .../file_picker/file_annotations.dart | 28 +- .../organisms/file_picker/file_compress.dart | 37 +- .../organisms/file_picker/file_edit.dart | 30 +- .../organisms/file_picker/file_picker.dart | 343 +- .../file_picker/file_post_processor.dart | 6 +- .../organisms/file_picker/file_rename.dart | 10 +- .../organisms/file_picker/file_validator.dart | 27 +- .../organisms/file_picker/file_wrapper.dart | 20 +- .../organisms/file_picker/giphy_picker.dart | 152 +- .../organisms/file_picker/image_crop.dart | 49 + .../components/organisms/file_preview.dart | 54 +- .../organisms/fiscal_date_picker.dart | 255 ++ .../organisms/html_preview/html_body.dart | 284 ++ .../html_preview/html_container.dart | 343 ++ .../organisms/html_preview/nested_table.dart | 91 + .../html_preview/table_html_extension.dart | 450 ++ .../html_preview/video_html_extension.dart | 174 + .../components/organisms/image_editor.dart | 403 -- .../components/organisms/image_picker.dart | 29 +- .../components/organisms/infinite_list.dart | 70 +- lib/src/components/organisms/list_group.dart | 89 +- lib/src/components/organisms/list_tile.dart | 197 +- lib/src/components/organisms/modal.dart | 36 +- .../components/organisms/navigation_menu.dart | 35 +- lib/src/components/organisms/profile.dart | 42 +- .../components/organisms/properties_list.dart | 52 +- .../organisms/quill_editor/html_parser.dart | 147 + .../organisms/quill_editor/quill.dart | 7 + .../organisms/quill_editor/quill_delta.dart | 61 + .../organisms/quill_editor/quill_editor.dart | 136 + .../quill_editor/quill_editor_page.dart | 579 +++ .../organisms/quill_editor/quill_toolbar.dart | 669 +++ lib/src/components/organisms/radio_list.dart | 44 +- .../components/organisms/search_app_bar.dart | 79 +- .../components/organisms/tab_scaffold.dart | 38 +- lib/src/components/organisms/tags_list.dart | 22 +- .../organisms/temp_directory/io.dart | 6 +- .../organisms/temp_directory/web.dart | 2 +- lib/src/utils/assets/animations.dart | 26 +- lib/src/utils/assets/icons.dart | 778 ++-- lib/src/utils/assets/images.dart | 75 +- lib/src/utils/localizations/localization.dart | 10 +- lib/src/utils/localizations/translation.dart | 47 +- lib/src/utils/theme.dart | 5 +- lib/src/utils/theme/colors.dart | 401 -- lib/src/utils/theme/input_border.dart | 148 +- lib/src/utils/theme/text.dart | 55 +- lib/src/utils/theme/theme.dart | 671 +-- .../theme/theme_builders/app_bar_theme.dart | 54 + .../theme_builders/bottom_app_bar_theme.dart | 30 + .../bottom_navigation_bar_theme.dart | 25 + .../theme_builders/bottom_sheet_theme.dart | 28 + .../theme/theme_builders/button_theme.dart | 79 + .../theme/theme_builders/card_theme.dart | 32 + .../theme/theme_builders/checkbox_theme.dart | 54 + .../theme/theme_builders/chip_theme.dart | 47 + .../theme_builders/date_picker_theme.dart | 24 + .../theme/theme_builders/dialog_theme.dart | 24 + .../theme/theme_builders/divider_theme.dart | 25 + .../theme/theme_builders/icon_theme.dart | 18 + .../input_decoration_theme.dart | 79 + .../theme/theme_builders/list_tile_theme.dart | 48 + .../theme_builders/popup_menu_theme.dart | 32 + .../progress_indicator_theme.dart | 19 + .../theme/theme_builders/radio_theme.dart | 48 + .../theme_builders/search_bar_theme.dart | 28 + .../theme/theme_builders/slider_theme.dart | 34 + .../theme/theme_builders/switch_theme.dart | 46 + .../theme/theme_builders/tab_bar_theme.dart | 38 + .../theme_builders/text_selection_theme.dart | 31 + .../theme/theme_builders/zeta_theme.dart | 152 + lib/src/utils/theme/theme_constants.dart | 47 +- lib/src/utils/theme/theme_data.dart | 479 +++ lib/src/utils/theme/theme_loader.dart | 41 - lib/src/utils/theme/theme_provider.dart | 101 - lib/src/utils/theme/theme_service.dart | 88 + lib/src/utils/tools.dart | 2 - lib/src/utils/tools/app.dart | 271 -- lib/src/utils/tools/compression.dart | 113 +- lib/src/utils/tools/controller.dart | 2 +- lib/src/utils/tools/crop_image_helper.dart | 211 - lib/src/utils/tools/frame_mixin.dart | 2 +- lib/src/utils/tools/keyboard_dismiss.dart | 23 +- lib/src/utils/tools/measure.dart | 17 +- lib/src/utils/tools/modifiers.dart | 19 +- lib/src/utils/tools/nested_flow.dart | 19 +- lib/src/utils/tools/tab_navigator.dart | 169 +- lib/src/utils/tools/utils.dart | 237 +- lib/zds_flutter.dart | 5 + localizations/ApplicationResources_ar_SA.json | 142 + localizations/ApplicationResources_bg_BG.json | 142 + localizations/ApplicationResources_bs_BA.json | 142 + localizations/ApplicationResources_cs_CZ.json | 142 + localizations/ApplicationResources_da_DK.json | 142 + localizations/ApplicationResources_de_AT.json | 142 + localizations/ApplicationResources_de_BE.json | 142 + localizations/ApplicationResources_de_CH.json | 142 + localizations/ApplicationResources_de_DE.json | 142 + localizations/ApplicationResources_el_GR.json | 142 + localizations/ApplicationResources_en_CA.json | 142 + localizations/ApplicationResources_en_GB.json | 142 + localizations/ApplicationResources_en_US.json | 142 + localizations/ApplicationResources_es_CL.json | 142 + localizations/ApplicationResources_es_EC.json | 142 + localizations/ApplicationResources_es_ES.json | 142 + localizations/ApplicationResources_es_MX.json | 142 + localizations/ApplicationResources_es_PE.json | 142 + localizations/ApplicationResources_es_PR.json | 142 + localizations/ApplicationResources_es_UY.json | 142 + localizations/ApplicationResources_fi_FI.json | 142 + localizations/ApplicationResources_fr_BE.json | 142 + localizations/ApplicationResources_fr_CA.json | 142 + localizations/ApplicationResources_fr_CH.json | 142 + localizations/ApplicationResources_fr_FR.json | 142 + localizations/ApplicationResources_hr_HR.json | 142 + localizations/ApplicationResources_hu_HU.json | 142 + localizations/ApplicationResources_in_ID.json | 142 + localizations/ApplicationResources_it_IT.json | 142 + localizations/ApplicationResources_ja_JP.json | 142 + localizations/ApplicationResources_ka_GE.json | 142 + localizations/ApplicationResources_ko_KR.json | 142 + localizations/ApplicationResources_lt_LT.json | 142 + localizations/ApplicationResources_lv_LV.json | 142 + localizations/ApplicationResources_mk_MK.json | 142 + localizations/ApplicationResources_nb_NO.json | 142 + localizations/ApplicationResources_nl_NL.json | 142 + localizations/ApplicationResources_pl_PL.json | 142 + localizations/ApplicationResources_pt_BR.json | 142 + localizations/ApplicationResources_pt_PT.json | 142 + localizations/ApplicationResources_ro_RO.json | 142 + localizations/ApplicationResources_ru_RU.json | 142 + localizations/ApplicationResources_sk_SK.json | 142 + localizations/ApplicationResources_sl_SI.json | 142 + localizations/ApplicationResources_sq_AL.json | 142 + localizations/ApplicationResources_sr_BA.json | 142 + localizations/ApplicationResources_sv_SE.json | 142 + localizations/ApplicationResources_th_TH.json | 142 + localizations/ApplicationResources_tl_PH.json | 142 + localizations/ApplicationResources_tr_TR.json | 142 + localizations/ApplicationResources_uk_UK.json | 142 + localizations/ApplicationResources_vi_VN.json | 142 + localizations/ApplicationResources_zh_CN.json | 142 + localizations/ApplicationResources_zh_HK.json | 142 + pubspec.yaml | 45 +- test/day_picker_test.dart | 9 +- test/test_utility.dart | 8 + 379 files changed, 25093 insertions(+), 9767 deletions(-) delete mode 100644 all_lint_rules.yaml create mode 100644 doc/assets/calendar.png create mode 100644 doc/assets/chat.png create mode 100644 doc/assets/clock.png create mode 100644 doc/assets/cloud_fail.png create mode 100644 doc/assets/completed_tasks.png create mode 100644 doc/assets/connection_loss.png create mode 100644 doc/assets/dark_mode.png create mode 100644 doc/assets/empty_box.png create mode 100644 doc/assets/internet_fail.png create mode 100644 doc/assets/light_mode.png create mode 100644 doc/assets/load_fail.png create mode 100644 doc/assets/map.png create mode 100644 doc/assets/notes.png create mode 100644 doc/assets/notifications.png create mode 100644 doc/assets/sad_zebra.png create mode 100644 doc/assets/search.png create mode 100644 doc/assets/server_fail.png create mode 100644 doc/assets/sleeping_zebra.png create mode 100644 doc/assets/system_mode.png rename {assets => doc/assets}/zds-dark.png (100%) rename {assets => doc/assets}/zds-light.png (100%) create mode 100644 example/.gitignore create mode 100644 example/assets/colors.json create mode 100644 example/example.md delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/lib/pages/components/default_flutter.dart create mode 100644 example/lib/pages/components/html_view.dart create mode 100644 example/lib/pages/components/list_tile_wrapper.dart create mode 100644 example/lib/pages/components/quill_editor_demo.dart create mode 100644 example/lib/pages/html_view.dart create mode 100644 example/lib/pages/quill_editor_demo.dart create mode 100644 example/lib/pages/utils/theme_color_switch.dart create mode 100644 example/lib/pages/utils/theme_constrast_switch.dart create mode 100644 example/lib/pages/utils/theme_mode_switch.dart create mode 100644 lib/assets/images/clock.svg create mode 100644 lib/assets/images/connection_loss.svg create mode 100644 lib/assets/images/dark_mode.svg create mode 100644 lib/assets/images/internet_fail.svg create mode 100644 lib/assets/images/light_mode.svg delete mode 100644 lib/assets/images/punch.svg create mode 100644 lib/assets/images/system_mode.svg create mode 100644 lib/assets/js/quill.min.js create mode 100644 lib/assets/strings/es_MX.json create mode 100644 lib/src/components/atoms/border_clipper.dart create mode 100644 lib/src/components/atoms/conditional_wrapper.dart create mode 100644 lib/src/components/organisms/file_picker/image_crop.dart create mode 100644 lib/src/components/organisms/fiscal_date_picker.dart create mode 100644 lib/src/components/organisms/html_preview/html_body.dart create mode 100644 lib/src/components/organisms/html_preview/html_container.dart create mode 100644 lib/src/components/organisms/html_preview/nested_table.dart create mode 100644 lib/src/components/organisms/html_preview/table_html_extension.dart create mode 100644 lib/src/components/organisms/html_preview/video_html_extension.dart delete mode 100644 lib/src/components/organisms/image_editor.dart create mode 100644 lib/src/components/organisms/quill_editor/html_parser.dart create mode 100644 lib/src/components/organisms/quill_editor/quill.dart create mode 100644 lib/src/components/organisms/quill_editor/quill_delta.dart create mode 100644 lib/src/components/organisms/quill_editor/quill_editor.dart create mode 100644 lib/src/components/organisms/quill_editor/quill_editor_page.dart create mode 100644 lib/src/components/organisms/quill_editor/quill_toolbar.dart delete mode 100644 lib/src/utils/theme/colors.dart create mode 100644 lib/src/utils/theme/theme_builders/app_bar_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/bottom_app_bar_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/bottom_navigation_bar_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/bottom_sheet_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/button_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/card_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/checkbox_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/chip_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/date_picker_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/dialog_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/divider_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/icon_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/input_decoration_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/list_tile_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/popup_menu_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/progress_indicator_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/radio_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/search_bar_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/slider_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/switch_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/tab_bar_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/text_selection_theme.dart create mode 100644 lib/src/utils/theme/theme_builders/zeta_theme.dart create mode 100644 lib/src/utils/theme/theme_data.dart delete mode 100644 lib/src/utils/theme/theme_loader.dart delete mode 100644 lib/src/utils/theme/theme_provider.dart create mode 100644 lib/src/utils/theme/theme_service.dart delete mode 100644 lib/src/utils/tools/app.dart delete mode 100644 lib/src/utils/tools/crop_image_helper.dart create mode 100644 localizations/ApplicationResources_ar_SA.json create mode 100644 localizations/ApplicationResources_bg_BG.json create mode 100644 localizations/ApplicationResources_bs_BA.json create mode 100644 localizations/ApplicationResources_cs_CZ.json create mode 100644 localizations/ApplicationResources_da_DK.json create mode 100644 localizations/ApplicationResources_de_AT.json create mode 100644 localizations/ApplicationResources_de_BE.json create mode 100644 localizations/ApplicationResources_de_CH.json create mode 100644 localizations/ApplicationResources_de_DE.json create mode 100644 localizations/ApplicationResources_el_GR.json create mode 100644 localizations/ApplicationResources_en_CA.json create mode 100644 localizations/ApplicationResources_en_GB.json create mode 100644 localizations/ApplicationResources_en_US.json create mode 100644 localizations/ApplicationResources_es_CL.json create mode 100644 localizations/ApplicationResources_es_EC.json create mode 100644 localizations/ApplicationResources_es_ES.json create mode 100644 localizations/ApplicationResources_es_MX.json create mode 100644 localizations/ApplicationResources_es_PE.json create mode 100644 localizations/ApplicationResources_es_PR.json create mode 100644 localizations/ApplicationResources_es_UY.json create mode 100644 localizations/ApplicationResources_fi_FI.json create mode 100644 localizations/ApplicationResources_fr_BE.json create mode 100644 localizations/ApplicationResources_fr_CA.json create mode 100644 localizations/ApplicationResources_fr_CH.json create mode 100644 localizations/ApplicationResources_fr_FR.json create mode 100644 localizations/ApplicationResources_hr_HR.json create mode 100644 localizations/ApplicationResources_hu_HU.json create mode 100644 localizations/ApplicationResources_in_ID.json create mode 100644 localizations/ApplicationResources_it_IT.json create mode 100644 localizations/ApplicationResources_ja_JP.json create mode 100644 localizations/ApplicationResources_ka_GE.json create mode 100644 localizations/ApplicationResources_ko_KR.json create mode 100644 localizations/ApplicationResources_lt_LT.json create mode 100644 localizations/ApplicationResources_lv_LV.json create mode 100644 localizations/ApplicationResources_mk_MK.json create mode 100644 localizations/ApplicationResources_nb_NO.json create mode 100644 localizations/ApplicationResources_nl_NL.json create mode 100644 localizations/ApplicationResources_pl_PL.json create mode 100644 localizations/ApplicationResources_pt_BR.json create mode 100644 localizations/ApplicationResources_pt_PT.json create mode 100644 localizations/ApplicationResources_ro_RO.json create mode 100644 localizations/ApplicationResources_ru_RU.json create mode 100644 localizations/ApplicationResources_sk_SK.json create mode 100644 localizations/ApplicationResources_sl_SI.json create mode 100644 localizations/ApplicationResources_sq_AL.json create mode 100644 localizations/ApplicationResources_sr_BA.json create mode 100644 localizations/ApplicationResources_sv_SE.json create mode 100644 localizations/ApplicationResources_th_TH.json create mode 100644 localizations/ApplicationResources_tl_PH.json create mode 100644 localizations/ApplicationResources_tr_TR.json create mode 100644 localizations/ApplicationResources_uk_UK.json create mode 100644 localizations/ApplicationResources_vi_VN.json create mode 100644 localizations/ApplicationResources_zh_CN.json create mode 100644 localizations/ApplicationResources_zh_HK.json create mode 100644 test/test_utility.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e08cdf..91b313e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.0.0] - 2024-01-02 + +### :sparkles: New features + +- [`9aeef97`](https://github.com/ZebraDevs/zds_flutter/commit/9aeef974505dd462610ff82675395400373d23be) - Add all changes from v1.0.0 internal. \_(commit by @ps9310, @thelukewalton) + ## [0.2.0] - 2023-09-11 ### :sparkles: New Features diff --git a/LICENSE-3RD-PARTY b/LICENSE-3RD-PARTY index 75ade83..29951d3 100644 --- a/LICENSE-3RD-PARTY +++ b/LICENSE-3RD-PARTY @@ -2,4 +2,5 @@ BSD-3-Clause applies to: - DatePickerDialog + - Quill ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/README.md b/README.md index 30bf0de..5f57537 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,16 @@ A library of Flutter components made by Zebra Technologies based on the Zebra Design System, or ZDS. - - zds_flutter example + + zds_flutter example ## Requirements Make sure your app meets the following requirements before using ZDS Flutter -- sdk: >=3.0.1 <4.0.0 -- flutter: >=2.10.0 +- sdk: >=3.0.10 <4.0.0 +- flutter: >=3.7.0 ## Usage diff --git a/all_lint_rules.yaml b/all_lint_rules.yaml deleted file mode 100644 index bf6b1ae..0000000 --- a/all_lint_rules.yaml +++ /dev/null @@ -1,223 +0,0 @@ -linter: - rules: - - always_use_package_imports - - avoid_dynamic_calls - - avoid_empty_else - - avoid_print - - avoid_relative_lib_imports - - avoid_returning_null_for_future - - avoid_slow_async_io - - avoid_type_to_string - - avoid_types_as_parameter_names - - avoid_web_libraries_in_flutter - - cancel_subscriptions - - close_sinks - - collection_methods_unrelated_type - - comment_references - - control_flow_in_finally - - deprecated_member_use_from_same_package - - diagnostic_describe_all_properties - - discarded_futures - - empty_statements - - hash_and_equals - - implicit_reopen - - invalid_case_patterns - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - literal_only_boolean_expressions - - no_adjacent_strings_in_list - - no_duplicate_case_values - - no_logic_in_create_state - - no_self_assignments - - no_wildcard_variable_uses - - prefer_relative_imports - - prefer_void_to_null - - test_types_in_equals - - throw_in_finally - - unnecessary_statements - - unrelated_type_equality_checks - - unsafe_html - - use_build_context_synchronously - - use_key_in_widget_constructors - - valid_regexps - - depend_on_referenced_packages - - package_names - - secure_pubspec_urls - - sort_pub_dependencies - - always_declare_return_types - - always_put_control_body_on_new_line - - always_put_required_named_parameters_first - - always_require_non_null_named_parameters - - always_specify_types - - annotate_overrides - - avoid_annotating_with_dynamic - - avoid_bool_literals_in_conditional_expressions - - avoid_catches_without_on_clauses - - avoid_catching_errors - - avoid_classes_with_only_static_members - - avoid_double_and_int_checks - - avoid_equals_and_hash_code_on_mutable_classes - - avoid_escaping_inner_quotes - - avoid_field_initializers_in_const_classes - - avoid_final_parameters - - avoid_function_literals_in_foreach_calls - - avoid_implementing_value_types - - avoid_init_to_null - - avoid_js_rounded_ints - - avoid_multiple_declarations_per_line - - avoid_null_checks_in_equality_operators - - avoid_positional_boolean_parameters - - avoid_private_typedef_functions - - avoid_redundant_argument_values - - avoid_renaming_method_parameters - - avoid_return_types_on_setters - - avoid_returning_null - - avoid_returning_null_for_void - - avoid_returning_this - - avoid_setters_without_getters - - avoid_shadowing_type_parameters - - avoid_single_cascade_in_expression_statements - - avoid_types_on_closure_parameters - - avoid_unnecessary_containers - - avoid_unused_constructor_parameters - - avoid_void_async - - await_only_futures - - camel_case_extensions - - camel_case_types - - cascade_invocations - - cast_nullable_to_non_nullable - - combinators_ordering - - conditional_uri_does_not_exist - - constant_identifier_names - - curly_braces_in_flow_control_structures - - dangling_library_doc_comments - - deprecated_consistency - - directives_ordering - - do_not_use_environment - - empty_catches - - empty_constructor_bodies - - eol_at_end_of_file - - exhaustive_cases - - file_names - - flutter_style_todos - - implementation_imports - - implicit_call_tearoffs - - join_return_with_assignment - - leading_newlines_in_multiline_strings - - library_annotations - - library_names - - library_prefixes - - library_private_types_in_public_api - - lines_longer_than_80_chars - - matching_super_parameters - - missing_whitespace_between_adjacent_strings - - no_default_cases - - no_leading_underscores_for_library_prefixes - - no_leading_underscores_for_local_identifiers - - no_literal_bool_comparisons - - no_runtimeType_toString - - non_constant_identifier_names - - noop_primitive_operations - - null_check_on_nullable_type_parameter - - null_closures - - omit_local_variable_types - - one_member_abstracts - - only_throw_errors - - overridden_fields - - package_api_docs - - package_prefixed_library_names - - parameter_assignments - - prefer_adjacent_string_concatenation - - prefer_asserts_in_initializer_lists - - prefer_asserts_with_message - - prefer_collection_literals - - prefer_conditional_assignment - - prefer_const_constructors - - prefer_const_constructors_in_immutables - - prefer_const_declarations - - prefer_const_literals_to_create_immutables - - prefer_constructors_over_static_methods - - prefer_contains - - prefer_double_quotes - - prefer_expression_function_bodies - - prefer_final_fields - - prefer_final_in_for_each - - prefer_final_locals - - prefer_final_parameters - - prefer_for_elements_to_map_fromIterable - - prefer_foreach - - prefer_function_declarations_over_variables - - prefer_generic_function_type_aliases - - prefer_if_elements_to_conditional_expressions - - prefer_if_null_operators - - prefer_initializing_formals - - prefer_inlined_adds - - prefer_int_literals - - prefer_interpolation_to_compose_strings - - prefer_is_empty - - prefer_is_not_empty - - prefer_is_not_operator - - prefer_iterable_whereType - - prefer_mixin - - prefer_null_aware_method_calls - - prefer_null_aware_operators - - prefer_single_quotes - - prefer_spread_collections - - prefer_typing_uninitialized_variables - - provide_deprecation_message - - public_member_api_docs - - recursive_getters - - require_trailing_commas - - sized_box_for_whitespace - - sized_box_shrink_expand - - slash_for_doc_comments - - sort_child_properties_last - - sort_constructors_first - - sort_unnamed_constructors_first - - tighten_type_of_initializing_formals - - type_annotate_public_apis - - type_init_formals - - type_literal_in_constant_pattern - - unawaited_futures - - unnecessary_await_in_return - - unnecessary_brace_in_string_interps - - unnecessary_breaks - - unnecessary_const - - unnecessary_constructor_name - - unnecessary_final - - unnecessary_getters_setters - - unnecessary_lambdas - - unnecessary_late - - unnecessary_library_directive - - unnecessary_new - - unnecessary_null_aware_assignments - - unnecessary_null_aware_operator_on_extension_on_nullable - - unnecessary_null_checks - - unnecessary_null_in_if_null_operators - - unnecessary_nullable_for_final_variable_declarations - - unnecessary_overrides - - unnecessary_parenthesis - - unnecessary_raw_strings - - unnecessary_string_escapes - - unnecessary_string_interpolations - - unnecessary_this - - unnecessary_to_list_in_spreads - - unreachable_from_main - - use_colored_box - - use_decorated_box - - use_enums - - use_full_hex_values_for_flutter_colors - - use_function_type_syntax_for_parameters - - use_if_null_to_convert_nulls_to_bools - - use_is_even_rather_than_modulo - - use_late_for_private_fields_and_variables - - use_named_constants - - use_raw_strings - - use_rethrow_when_possible - - use_setters_to_change_properties - - use_string_buffers - - use_string_in_part_of_directives - - use_super_parameters - - use_test_throws_matchers - - use_to_and_as_if_applicable - - void_checks diff --git a/analysis_options.yaml b/analysis_options.yaml index a730826..6bfc3f6 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,45 +1 @@ -include: all_lint_rules.yaml -analyzer: - exclude: - - "**/*.g.dart" - - "**/*.freezed.dart" - - "test/.test_coverage.dart" - - "bin/cache/**" - - "lib/generated_plugin_registrant.dart" - - language: - strict-casts: true - strict-inference: true - strict-raw-types: true - - errors: - included_file_warning: ignore - missing_required_param: error - missing_return: error - deprecated_member_use_from_same_package: ignore - parameter_assignments: warning - switch_case_completes_normally: false - -linter: - rules: - always_put_control_body_on_new_line: false - always_put_required_named_parameters_first: false - always_specify_types: false - always_use_package_imports: false - avoid_classes_with_only_static_members: false - avoid_positional_boolean_parameters: false - avoid_types_on_closure_parameters: false - cascade_invocations: false - close_sinks: false - lines_longer_than_80_chars: false - omit_local_variable_types: false - prefer_constructors_over_static_methods: false - prefer_double_quotes: false - prefer_expression_function_bodies: false - prefer_final_parameters: false - prefer_int_literals: false - sort_constructors_first: false - unnecessary_final: false - avoid_catches_without_on_clauses: false - avoid_annotating_with_dynamic: false - avoid_catching_errors: false +include: package:zds_analysis/analysis_options_lib.yaml diff --git a/doc/assets/calendar.png b/doc/assets/calendar.png new file mode 100644 index 0000000000000000000000000000000000000000..77d9be300a940bacdba9bfeba6ad9f5cb787792c GIT binary patch literal 7874 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 MUZ~5J$yfya4{W@?rvLx| literal 0 HcmV?d00001 diff --git a/doc/assets/chat.png b/doc/assets/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..37724866c1ca4b93e77b13ea59b6be7e24aab121 GIT binary patch literal 21800 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 NfErmCez@xP_&)_fmjnO+ literal 0 HcmV?d00001 diff --git a/doc/assets/clock.png b/doc/assets/clock.png new file mode 100644 index 0000000000000000000000000000000000000000..9d1c2fecab861f97456164dfca37de9c56bbab92 GIT binary patch literal 10389 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 OhwArqR7>w#hx`w{=o`NP literal 0 HcmV?d00001 diff --git a/doc/assets/completed_tasks.png b/doc/assets/completed_tasks.png new file mode 100644 index 0000000000000000000000000000000000000000..0385036c64ac9738fe864587f99dc9020fead19e GIT binary patch literal 6345 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 literal 0 HcmV?d00001 diff --git a/doc/assets/connection_loss.png b/doc/assets/connection_loss.png new file mode 100644 index 0000000000000000000000000000000000000000..4cac6cb9668174a5aa889d3b10bc9d990e2f9816 GIT binary patch literal 6636 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 M&tr^A&N@8$e=?w4QUCw| literal 0 HcmV?d00001 diff --git a/doc/assets/dark_mode.png b/doc/assets/dark_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..8ba420669c01a5f4bec7a47783dfef418a3240a8 GIT binary patch literal 3350 zcmeHK`&ZLP7Qf$b5|Tg>Eai=WkD}lz6%nGf5D^g-gaRufk_0)(qX;onBw*mH?iMQ` z9IGPWRu)%06p*kh0R)m*G|@&0TgAi*Cfx{V1LcuGk&tA+oc#y-yO8~Im6CN4^fZ{3&6boGF^Per?g31n0$OW*nTj~hZTyw%fBsXSv z2;A;>dy5Z5YDM?RS2n}rqbJfB*9U)#CCvMx z*w_liOr$xl>usMy*(0&EJ@lSXeF@an8m{r3-k1MbN+K(Q7_@FBJmd74Pcc*pSM2{0 z)HpJ=@gBoBrhMAO9G&gpti=2^hvhWQ=G%mmrQrhbE4MMtTd*oTlydFF-#6Hf#qYX! zyw9xdF(qW1#7AlrRqfZ1Rp+Sm3yoKLO^s0WQ#NDrat57jR2w|Cs)0M)G}3JAI_ixbb1f|Ja1hJ7wzsMjex&(&pfuO+LtaQ0wiA1~X_=9mMW*e0+T-4@W$r5Uf|o3n2Q4a4#>M7{;s7Tj zVJu^4F~_0h1^Pz*#)FolkR71o(|RM@%S^qajACp2`Q)1u`5L zCuh#o2_j&jCi8`X+_|m+%Bw-YMQBv5!%9;u2d+}-Q7Q7`abpyT-4=n=%=oCkl{A_g zVdJa$5KedcZqVzqk!ER2{fa~|MvP2(@PiaT1kl%efieHB4L_`-^Z=0_9Cl3X(iN~J z#j39AxN@`>J?Ifd@J~SpO25}%;~b$dO@4hy+be!+qG-gR#`2J05)6q;Foj;NnG#({ol)lSdjZi;)RJ)2O`}AKmOU} zz@tDNLGhgz4g|%~$%gtrE6(p1Rx3V7nyUFtIep^pfqtL%WOP6_&#K0a@2n3rFBR#NmMq@k z+L|`ffILnX0OFdS1P1!-Je3}7;0#zCtV-&7*RdK3{4xp8Uq4-{_n&cH;9#k-C;JKk zo45*k|DbdaNAZJ~murjnc>!-}ZS@p0_CKoQ#N^1R>I%+28bG|unHeH^WfrDCBGv`Q zg1Wx!3%M{|MywM}Pna1Sd?_f+#&BrPl<^pcHj(mMpK_?A|{@n)WQ$ zcq3izAQqIhV6G%~z+9?cP+J??xbVrE?grC@l8bajxX zI1;5Q&}^Mc`K0et-NN4%kHVBr@=d7b>-wa&4AfH^Cwq#-B8zu;8!GTOe4_h^egRjf zPaT5bfTAI3tATXf!c*3vTgYNC2WKSoL{#kb&YaBf803_D{s|uXyW91|$|lMACq8-Y zqFRs^iP9DcTM6Pg8FEj9#*Alj@8`td=U8C84JAdApX~Xm-80;=OH`28W^$*cEu1hA zu*Rn=`b3&V`RyhCZ0<_hM{%oi!uCrdi^sLW-P4B4(M6#!RevE$k@JHckslz>o@e5u zTExs=So{DHH`RQbxSH~6ow~VPQCLxH5DG=plUBd)e}K>O94rRUz2k+7mX3-gqdmL! Khu#iho%uJqKBET! literal 0 HcmV?d00001 diff --git a/doc/assets/empty_box.png b/doc/assets/empty_box.png new file mode 100644 index 0000000000000000000000000000000000000000..ad8fca07c9827247804d3f550a8191716e222238 GIT binary patch literal 3898 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 literal 0 HcmV?d00001 diff --git a/doc/assets/light_mode.png b/doc/assets/light_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..c8185cdb8e54dde03097bc777d4594dfc97b5f36 GIT binary patch literal 5173 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 literal 0 HcmV?d00001 diff --git a/doc/assets/load_fail.png b/doc/assets/load_fail.png new file mode 100644 index 0000000000000000000000000000000000000000..d5fc734c3964f9fede7bcbd2ecb7c0cfcb5d08be GIT binary patch literal 5001 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 MTs6=vSGNoOKh6B+@c;k- literal 0 HcmV?d00001 diff --git a/doc/assets/map.png b/doc/assets/map.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad4ccb56f897eb43fd50b40b4526cbcf431d978 GIT binary patch literal 10887 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 UCu~jNe}97W`X+jB&*CHhAEOWOi2wiq literal 0 HcmV?d00001 diff --git a/doc/assets/notifications.png b/doc/assets/notifications.png new file mode 100644 index 0000000000000000000000000000000000000000..29a669464fac8536d358ce8096f82f02a18bdf32 GIT binary patch literal 20598 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 N{r*Gy%544U{{t1}`-=bo literal 0 HcmV?d00001 diff --git a/doc/assets/sad_zebra.png b/doc/assets/sad_zebra.png new file mode 100644 index 0000000000000000000000000000000000000000..dd62ad27bd3ec8f8bb2b09277699b2ea0cafd7b1 GIT binary patch literal 8577 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 Msq3i~-+2`FA2LmQPXGV_ literal 0 HcmV?d00001 diff --git a/doc/assets/sleeping_zebra.png b/doc/assets/sleeping_zebra.png new file mode 100644 index 0000000000000000000000000000000000000000..d9181726884ac854cc1db4cbfafc0c9f1a17a30d GIT binary patch literal 42015 zcmXtf2RN2**#7gHudLT9dz8JEO-T0Mls&R%cGfGKqC!@7$R^qA6%w*Cvq$D@lRf_T z@B99rgM-7tbKm!MU*o*a>wIFgG!zN%P~U+dh)`KcP6vW8z>lzbI1c!>^SMS8e8Y2B zdgcj1tY-gx!R)=n2*EF@yyT6%blq&dd@WzTfP8&@c^zDxJgqI=U+}uUw9D9)q=q0y zNLlWQp5LeKIsZ>4`e|pkLyfhDdjb01q@-|TEv(S@@+Mj&v|SYLn3*F_2p_I&u&)GO zZ+>|cyAm0OHH)qIjGW>b1(wadKPgyW-+MKo4gRIiH`fIOhv?yAGH*83?;7Z@U%&dt zmAWgwu59eR=Q-p*C?=~Cvs^4Aobgys#s8ZnC6|!8F;jsF4mTz#-^CxwDl$sgR~ZA9 zw7asBxen7SK|w(@$h_tyuGsn?Jw3*rjk8O#(T0?f9$ygm@s7EJ|G`KY>t|FCWuC(Y z;Laih)>`oDYCX=!4bFeQGM(OH$1W4*l0uW%QIU~mr4G|Hp@uL;OdjFdOw25tT|t7C z!rtEA=E<^WiS@-U@(0+alg*(bm~OCmYy;T$!ZqAb+z7;}Du1)Tt z;Pt*H*r!<(>9skuOu5h_H~fNydLrSot%Qvc>KTE^Mzv<#%&TD-(nMBQw71`SBv@-F zsn~CNT`)6sHKHVtIXwr?7`!8bJBq+2HS|4s?E1QRNK7x&5TSkL#hr%J&sIN7(+h)& zD=YVWDlxT_?#;CLdot4}WOId|5me2h{Z1@Q;0K*L#mB8TH#biz!?eju^)M{*y~Km6 z5X)RBDzhG)+e;HG{XoSUC-{TppT-p!p1 zO)+K+oKQy|uq;0ClU8&1h*g1k!;+>(`+tT+tUeqHJkuHxp=?q$YBeqR|Bs*-z`6Y;wRb-*X+fLHG!uUq1~ zAWr^=4}Y6*->t;BnMWH*9;TS^`u6oDbNRlai_Rt>CO%y~ zI+s!(eHDR_i0ig`b$+<|Ea$Jcb8w-ngsFUTo{2~Mf&Pl0k=(#&wQO=vvlN1GPG?fGx?9JIMeic_Amvw`-OtI5qqXa zHcR*!9-@B#Fp{Ux945 z)~~^4?NYhd;`r@o!M1$oRR~vO! zBVyAFTc2fiFNN;K=-US(M57J`e(#b7CMEPUG|careZjII{=In|5RNc>MHe*`Bn7;& ze)5SZ2Z%Xi6@NnEOd-C4tCyU~7kP9p=YKB#p*!j5=;|>l55S&jgb7yIYc-Mh|CvFQ zN;LZr(Y|IW*qLP1asF`Kl3+*|4;5$gFs<`*QV1*^xY|1Ne#NUfZhL$C4Mz1*`h1g3 zr+avx($!dREvz%z^3fNoN!e9NLCt(=YHdX9esoHv7xB>~OPwfbOx#y=gGbDJewQ3=8g*P6ZrA9qw&Qj2*D*G*yH^-ba;V z2jGWJG~?EwrW`)H%PwZ0)?FaD=^PVohW3Ux11pGhTOE|5I?Q^spH9E-ShQ;;`tJJl z=~G2$&+E(iQ*Tr0{@l9OLhXtaEzZ-SG_@ZhBH`&L>LXnR%bwg-bZ6qj>)uKM%vYXc zwJOlv7Z1~{KPNGqipNtQ->t-~GG;{h5epAo?!_STc*&5?!p%7P$95mz>6q2|AFV}C zhK`jnL?h5$&zGGQ4)t?7(eF-_r=`Byr>Q`FuXXzNtX*oN6xOc}sZx|V7S`M^-G15D z{1Y9}^WDQvq5VBO8yGtIWbCtQmofXH;OfycQnM&sriE>yFQgFgKut*T6`kVSl2Xn! z5M7k3neCs*9}#rU4=4oY=y4MI(>*Q!pcCxs?(SYY=`r>ut{YZHHp$pP(mrs&Ctrev z5>Zf4NDsYT_ofxv76*sX6{YoAjke=>F-M_Us8jqF^#~X(KQB}!XE!C2_J)Mktc&$ZDoQ6#;Tt5fUdkNJ?0aMDe_gG0 zQIxBe2LcvqZ~^9mSsY2Wf>~h^k$RVZTjOH5*86henK!shT?zKHxbIXRe^6shI24B~ z2I&fttSeh2Pv$l#9GVR#8v4`W$PA;QSp)97=3H{t%;~}nJitf#(2QkM0Bn6OF5cv4 z>gp%#^h-ln39ZKc>eFIBeobJa(pzyF9*5_FUY8<4B=>g!L%9KHJI0B{*qVip1!)e zvIMmUz^&*9ZG01qqC;qY6E=ra@o-aWUKj)lG9+a29DXn%cYmqpdJ7YPI|Ron9;!4n zUr^n+2Ax4DSTKG+T=cG}&t!X}7JCwahIbnj;U0YZ?)TsOP4_dN0@P@h)N6yG)8_^- zj5!{Y8P1p;hSqYT;IiPm{UJ`If*M40Bo1ZwWA2^wzqP);__s7TI7mj&=~s?e##%HQ zBOPqTgPf2;I(?onFH;6`*;#AKA3?IwGaq{Y;TAc{_wQy87a($Q{DC zjKXap>LiN{iG^r5VU*O=TfYSdl8@${lCW-=Ks_GmX9Ovjv_NOmhGW$Mn1D@{W5&^s za>1$pa}w~@7F>|!3EWE&%NI(_hl1+o;+x*qA8-OP525=8f_dBaaM%`3+i_RRYfAI0~&jBz` zD0HZYMEu3J5>*PMGBk>`l~Jl=>zHvrxLSxh9+lvrXmt8qE3Nmrn7Ss(V!G;0w;uwO z>w%&|0c6q2ds3bh5rJS+=Fr5rQJnm@es_qY;d@+umTvJF_NG^pGQ4_Xr!AkLw*H4Xee+i3Se?i-sAkureMj{jGJdN+4w=6$;K=NEl>kE_dlIJa8DJ_ zXDLPqA1140rf3u?Mj*`Hi#6NPpH0{e&7Y=xa50Noq+(Eq363eqq^a4KCmoUk2$jab zn%JALyqJENo11Hhg%L`u$}uE2ckDEhkGh2!GAAk<8bkss;)f&twetmH6LfCu?(H!g zi4z%L8+m<2#^;ducFztzZ~TpB%sKdI(FHQ0=I12zr>1jaBBCDvep5A7ER;A*TkG^4 zX^Y%G_h#Pbu~3@)=L7&3jfWp*Hi$0oMf2j3f%xsu4$l)O1*Ud8U($AH0&jTGMg_C~ z0!r5ArMinrQld`qy$rsprV54v^u;M=DCkW63HKEwW(*}Ma0UVNEkR$%uqHNYP5z_M z@cyXA%7-zSizA%>Qm5LeY$zloYv{>S4eW1+EK6|#m3*(=<5VCs#yp4Vgl&8K|D0Hj z^@z!Ik^!4OFEBRCO}JT$w%WPc%%Y|O-L6qI+9NSG#3Ohn@O{a>L8{U?J4r%7lwxYv zo1J&mD4tKjo0=1bkR@-4@37NQD;jmHy;wdtI504sye$A-T3pg$5sF0kN8wl`VxO0( ztF@^@8pPOON87R$%tW=7H=0LdHMRAT7^JvN|1^B_U zn#x|=no?lWh(;4vr~z(d8)BnED6XR7-&ldB@ix6paTYcnm*-9F{RC_IQ8?vjAV^)l zhnsTrm-6waSR0<40J?ZCj2lWO7hu!TZ)KALXTt{%9z2Lq3Fgn#U?@gkR1$PfeG|Px zXIS0sHZ*|Uqly#&9&Ct%iz~tNEmxW2wtpApIP6?byRVo0$R_6KZvob`w~Gs*Pb#0j z)Kh*7HE6)AJJFPZN?ge*Y=gmeBJ7+}YRof#e8A;n z|6a$e3Vg6+YM28{n4PW~Np3YP6>F<5ny*T(_c|GIExi7*gmP;k>c!!N?f+D$#N5wi zM}ZO;Re@f>7S?V%5Sca@iIr#yN8G!^Bn&_?@z-^i*4F7uN;O3v|#0Nhz3Ha#G#+l~}u=yPmXrn3fzD zVi*!(zSavmr2jzKgmj;S)ZitOPur;$1{%_>+DMvZo@5nb91KU50AIcen7y7XTu}W1 z0-obAePrHz6FiyS9BdHX>K5fjx!O7NIZ25_fMDfZ+V_?-S!L+fIiF1S6Kg@>Q`W?D zbB@(2MBd10%G5Wb`p?_RNoA|jje3$%9mI|s?zz#EFd0l%2;eE>O7w-GW9f7xIUEa) z69#fo%GGH_M)N(Dg5O8x08gDu$93O->t)4;NYpW73{O1}M=)r0-X>o(w0u(S#`@q? z9C4X`teCfaYo2r+i(+7}v@_gFLcG>um*b}lycx3K-`G?SHuqs+3i!%J#ZG>Q@2qC< zJWr`lRi}@pH9og6(Bvk|+lpr&v-0V)4|)$EvnHZsXe`-OE8^3BUHOXl?K7{g7&*>XR}vwiHxr-=2pCEDISI+r12tTOOet6bZ-oO=Juzj zr#E(X3hL`qPELH55Bxgku1;AIa704S=EepfZxVKQUDGo%(2jy#L^^$d)-j4jET5Y7 zXpP#Qi|)UfwA@bCjHRG?2!jx^CIHJ&_)YP@F=Qi+AqKQ1S~mI-^0I}fk0-s51Uzwj z`!jgr;Gl+grw9}Iosr+aWqo}`0IdC1TTAj*;k5BpE=)3GXx*H(K$33X={~ zIMa#S%e!HZLj5bB{=pZ*SS(0OODjcMR<2CN2`nZ8sJ(Y_dAYanFC|9K%Erg%gn6-N zY`SUkjzhWv_uYV-!i9+m1!hu*;|zmw9~Rwa1zd3niI{Gywhdn%c%32lsA z+r-F-Kw~8XXfXd{TfDaxTfCUCM(mUPBsE00HA- ziqkg#MXG`p{a(PUS0}agNWj%dF&13m(Cw`705(d0Gd78)rf`;eG4oVzu7;W!V3g~NpqZSt} z+5wk!GE%iFg&p=}`Jka`X)@I`AETzGMyRGt3w}@vP-Ae8MeW<}k&av3K+01EI0K-9 zdzNd`!<+UoNs4~zqBue1df_^)Dx2Ys?BhW)pp(c#EKA;N;)EH(Zj;qmdHA$Pysw2& z<1*hXP@hO+bDm@gcq_Tk#?3|L_WMp?W}A4AsXws9}>DsKXw=s z&0d}=79Cyn@MX`goQB_(!NX*3ZBOJBq95XylTUaEd=Bt|8cK7YBC|01T(TD!k z)U2#Rt*R^J&PS$B{=umrmbdzV;>KEBh(HwmK}=@NrmC@KIvT_7;$tx61zvof+_fz~ zZb2HeKyd)QVarD2ySNJDn>bVccrnh49`Sz6TX0p3SXRrh@&sO6R9qZmG0eb%XYH9Y zB;$kgwPsb?msf9LR|gN(B^ij$lI*_1=$@54Kc_mxuc7R|VJ$Pc4Q{`30nt{o?&{#NIX;O3H$(i(MDq0IEhS_Hd%=|tFBu8g(fdW z(f!6=G(Tdtzh|}dG4WFtXb69+DVTVllV;?yuvSW;!z7Gt z3X$<3Z-kwPhbL?Pj1Vu4iZYcu#3cjyENWLhnHjqGxGIV=4*L!WcKn*Z>xI31zYK)` zLhxLY*dLpl_O`cetS5Uew)%$eZ1DZWw6q??pl$)E4#9Tju=#0QQ~8i!M8xJ_YE z8U)&;GhDT}OWZ?Zo)5nzyY|p8!CDIswF~UoAsek2ni`R^j$BaX2mxW?TEkTc$f|Kb z5wKb?)YI(w`LCpWz4B^zAP`P?`ieT1cf9zSI%KA%k}oOFFQV=W4Cq?191bxeVuvTD ze{IR(M^)OdylZ1Drysw^$IZ?E`0>tq;+;xR+3om@>weYEEq(p7&B?K1DAfNv~$0S78SC zpc{6vYxaRh$bPGi+Nd{b#EKskYDT+y#pFw`6ZNHZAm!>UI=z5 zy}8*nATplsTk1ESsx(Eo`&aK>T}kTd>b98(F@h9^fVY%aRt`;=%HZPQh<{(&S44Ui zB$aXn{=wMqvw7IqF=&)@r;O|r!%Qkvy6d_Bo2Y9{PS_L~4}fa*a@9l3?#YN{HqbXc zVSD}4=AoSm2On;p#y2;8Mnq0QL4?t-KE@cKBY8g`@+|sDo)xXb4&#YptVQh4%pxM) z-?y3ZA4zbPGEBWiP?x*7v;@Au?J09y$#EU1wUJTj-QMPY^ytyqK6MSn*`=ew@^;uq zjiLp{@H5JNgA>!TOHGgz6^XiXxL0)!e3;w+@xN9y;z~HI3Xx%f0=@ydQ%P5M)G+jD z%B2$r&~E&1_$VU}R3)NF%+)6U4e3e^O^XOE%ECdRc5rlj`GW2?5GKq$e_XGTw0?Ts zm5gQKtMkD;^+mAboAXV)&z7znSzw#xJhY7^iTS5)*51C*K!mShv7VKqV{8OA4JY4@ z5GcWqlU2lg8YVV2?7wQU2Sy%x|2@zB+Kv8Mq*FXLuJNy&TOJfDLH93;Fv%a!{XZ)P zNo%q|mpSNHBKwXUFF>#ugZwp@RKMdLJM4W;gDRri?)+xjv)|-#$NUvFy+-HCGxjsT z#zr(A%Js9hm8H*z^In0Mp1OtReBlbdcDR+|U*ZfIreuro!^F-5vwC}#+sAQ#!S<9` z6GObdCIVj{lwsU|&herMECnWvd&V`k>ZS}WT4WP3AsE4n+IyN+25sN-+p>#Dp<6^# zg*nz$&1C5I@`U@X8hsWu@4{J>9oe@MAdQHdTqaVqYB5{URmy_Q@-En<|^f>%E;Od#CcC)vNx8 zo{W+Z7Y~ND%%F{OuEqe&S(|#ouk-zffS*N`WW9N5U<$Nd_%6fRRv-v>5 zA?CSDV@B9AfHp$?DZ0snC2YChTKN06JzrnPvPiKC4*e6u?Wt>Bcyf1&1pz-iyuS21 zTAHIB-uWd(+->z9+})wSxmt|sqAqat`(Pkw@=aqFr=?@nOr+X?{x4W$DdGA#&G2&K zZ7p)$P8K)pNmEnPu;69l;)igy8uxWi{-tJFcl5{S$%|3?_#N&^b#2%7n<@g2vMgO+ zj*Ycp6zII~5hgr1v&{@UL9e(d{;O`9nU@_l-D?e$8k$NipRqS$LhgZ%PX-W=A16E5 zD;fz-$)I|T)LAw_oIDtwpTF@8bU$))buBC?=sxi&2>+jc0&jV6M$Nuze`+fY=OQQP#Lx)j>i;Rry z?@Rr?EK>@ORS`hjeMMhE-RrMS6yI|XuUl2RYKm>YPsec2E<|5Ype|bpWZ_Q?4O4cC z{wXgObI%^oz8PP78*)z_)e|4tww4mCi6I@*(&F%*f#L}N*PG2>n(Tv-F8`+mFvi!i zhY?BVr1;V$GLBf?dOQ30d@SZT>Zfrr_@I-OsZvmJ415V2-6fA|Znn99emcqvoicSNL5L-fKL|V>*5)in_pzkK&bg&*#rcBA8h={_mB#P6mR0tXbO8 zxvb@HXWS(ic`uGU`O6t@yYz~MB?Gso_ujSyjGvZhbbNfZuQw^cgJA#BSZ$3IUhs;J zX4_PlVrvW?zqt4`DFKcf*2jR65C9)*YDQ0Zf)X~P#*ZTT*PnJKuF!tNA93&TaN>>13YaM04 zBd_8gT7ka(tGpgNI-81vFnJSZ=W3w90tt_LU-zSm&5q|lmi}4S*6j2a#c?T$rC98y z4$=jWM6`_i!eoV!C@RXV{`bgBMJFBR!} z@FxKQ%{+TS__DIm=5OQUSz9+uJbpfJgiZbRleWx@Kdr_B>JXd%rp-)U6b&_z$NtT{ z$PxR0dj(Oy-TypIW`Pya5m1;cB#X0rgEFs69X5AEdXrFG26djZPfS(os)OBQ`AllE zcsj=oKi1XOj*QtXe0WOsAwqV^5NU^v7yH2VWecu43*>G2-{=gCl@?!ix0{OGzJ|5W zL6g$P6^HG`uV?Eyu-qOul(;5~56`CMJn}{zm13pmKN*zr*nFh1cF0n3cI4wT$i2UV z&R&YQ^D&@Pb#f{-R7T+erf(oFo+3)g)vF~TPX*cv1=Nl7kJiVZ`!lD#jNDr3``1t~Y7*Z%!2i40uUNkBHWY6f(j=|rRjoA6sh<2CG%b`*6g+>Rb zac`Iz3rwev0dQ|Z6~1Ltdjx5?uAbkBb4iiupj2=bBvn-4)}hzh{b_@**wt1~uCD*c z`m0!Q@K|p6`YeU&JRsUMyLkEVvH9P7zAg*s(`>p=i%#t`KR3LvBiJv8r>D2%EiG!2 z4!3|J$3NK8(0OTF5UE!RIZiD5N7Px{d^o-9i!frBYW9!(*!+`VeyhLA4|)XZDo_mCD#0NN~%C>$O>hG zOKI7Z+biCo`ihW`MNuUZu3uYQ=i&xlOC|T(NdCc>s~%~52~BMoU1ALNXy{{DbSy{B zjGLkWi=}^*PTKH7_neX8(cRenX2JkX${TULXXQwpTl%4-p}48Ukxg2|h2~DZfJWK( zs;=`tJ7-EtySFwr+yiDTU{_$^;3^`aPs`XaS6x@20y%03XY3^F+>qa!yj08|DXBXZ zV!pbe^0OG8M%QbgDzkVevA5^f!k+F&4Sej>*;4C3W=rFQ>GEA&(n+WWuK(cqwK~AS zW5P{!wK1VCS=D>-@Cg%EW@csuJtK308cf=&{AoAU?+z?zj|^H``ZHatw9yodxqr7_ zoFJ-GpKjaw=ONkE%AYN3Jcr?h=UM3SBFpEG&$$9dCJA;%4j+zg6Z~B(q|$VILcNv< zvF`~T&yyJ*G(9cPR?z3ZOGQJ|$-ga@)ga5D&YCFgUh}kDAtlC);GyUNiVcWPdikd3 zEASk#P*|puL*3mOAs|cU=XV|swA-NcHUD@5WeC}PU1pVs+T2xgQ2!vRCV%w;ffv5Q z<8@N00C!5EYs>f!Fu+gb0;bNi2SclG%)wPF2|(r8aUbn;J16dr=F2E@GPV7 zZO@8p7FCrF{DA7eLy@jaZC7A|$J~I39Zc4t-&HWLHu`l4lO{Xbk7LVSl#7YYYj^?& z)`lyTEri!dtUo)A;z{Cs{C8O%Fw-WbxIpfcgKqkV0q+jFWiKL;eBoIN<{kN=p`k<^ zt0{9ETnM-k{p(MB--oi1&uTdmbXLNLH@2kT$qc`Gal;yv-hbP2njd*O*Z!sC=ErBs zeWCyMb-!_8?XGp8vJuTmZ4A(eF_Pa2B5_}3OaL6XYR0t^-eg5owHWSe9dcs(4g_8C zHP0Riw2%5B;2QLOdLji(^hzj1SzEzWmTYcItvX^35BlaGz+45G3%SXEPm#5*$K$iJ z&i*`ybTbx-{|HCOyHjLGSf2-c)F1!hcKfiaMm1BtjkkMMpcHF_%-XIUeVi1s8?l{wl=K4MSY;iwLvmRa2DAm=M2 zMb5#Q+Ljfh0Vw+T@rvS}=BY8eI3g+UEC#Xq3K{_R_WbiK_!?R3B9M`uK0D1R$`S7V zqEEXzv`P&2Za0&!hK&T6R!VI zPjH)Y*sOKUq-HN@vGDR5J7Td^!6wKcg8*s>W(-G|zs%3Cs}ojzdTab+i7$)@>odF5 zU8haviQf+A|8%}n_`2Bj$v&15>TOb<1KA=_L|msNX}wZu+t{yM0crt5JBiQ-nY(Ov zLjW66lmFjAgqUfaDz=6hkxsV{ zm3*w`kJ0zvN3WJQ4IpF##R2OpI{#j$9M{>oe^fhLK@&3ZzaWn4>{?kfyii;3j|hp) zlTr1JwV1kiD{9W)a5XgZ?(W2J9iZ8&MPzD{blzf|W&X9KG1djsD&?ZlB3P8@T*A0e zw}>nE-f1Pf%6SX2u5D{@_|K=zmBFHcy;V{;)+{I7MB?GY<;|0-KGH#JG7A@nUe#i1 zs1nX3wd2JwVn3#{v~WQ(Wf9z`qrLSUB;l6wCTsEF(@8SabRh6IsXct|!tkF0qy9Qe)tjt>c$#n2VQ#n4F-XZ!}aJnk=b zT&dpCm27!2dyGy`Pv;IQRDTXq(EO4Yn+nBtDJJ;;886cXO_g(Awo8Pp(W{F|yG4?@ zP$YRlyqvK(yr*T=7!1~K*6+CQ5k>uH^~u>0MMnE; z2NRXE0nD&MUpN@6>|xYb9cc5N;VvTye2ke{XxG_}h}^0u^* zZ_~ttxB1PHE8lmKrIA4Dzvsmki|zF1H85AY3PhVSV4HzF75}5iefLq2*M>8UTkQ#F z?AHuGV_$tm988m2_vvGHWb#nUGeCSli1*1cVrF^W<81#kIrjHshg2+}*UXIQY`5pq z#PoFuYdJ6Y8Jo8~7^#iq>BN_;cKLpc{zQ-cPNz*blXSz_hZ)MEgOBm!AqySiZAXA_ z9}`)Qo*#O&$L8tr%}E{2y!N*C4m+w&`zRkWa0*eoK#tO}-z6U>NA4x76r76w31%mMXi6w) z4&i6KWvdgy;^&S?9`x0*uz@@8aTOsD^J|D!JujtvL+WTm^`hC0w+>_oO`V zjDc3i^ETE>g2~=-ue>CN=MQ$B4Xb+VeZ)C6|2ndc( zc@F9M4CzMPwoTARjB_KTrA>Z`$0O5HTUsJa&yZ^CXEibAlsEEaR29QK3n;-w|AbnF z{yiu$t1N^*Jt*+7Oc|_??Cd}vm{QX6_oCma-kh0 zo{HFt_esKQh`m73$lfx*_}lu2;EO96v}l8>{$Nt0dJEBO)7-MhmZnda%*dLnG+a`7 zjzZ~$X%&PIpQ`vT|NI%vrunANOwSm;F`|Ner2)|nd>CMb8t*e_Fc}TCd&nP9@lf8^ zkr%LVl9UV3?E)4_#>FE09wGaLj%1syfRhZFCxVA;9CdPxQt-z@kpOIcydT00-+PW( zM7}6MN3YU(*76j_8GG1bq>9`4r_c9<4ApVX)8eB}tXSsEmXpRXn4plarmmi*L8~T; z-7sJLgCbFiX|#;26BK;*$JDSd{a9csNgFYK`+!qR{k^6xT*C;~Q;95J*`E}2rj7Vu zJ&7mp;5_n?NX`f1I5kC%k`unXdScpQt1c4cGXA(@FCFLS>P!9F8WCBzKJKD)g5|%C zQPiJD1*bs&4Fw8cwX zk7;W|Byy2Ko?ak+tFa)XWQ`(Xz()>=kB3@)_^Tb>jU}^qCiOc&Cj}3gbjVyZUH9;+ zJ?SHVix11E1_ozpE=^)*YQB4n9I-mBMxH(Rq)0%^RO5Odq(5!m-1D;iVW z@RVCQw$`By(7Hzw#r0B1{Q>zMZFX{62XhsFjHC2a`08-h0H(+ZX6V|R) zlyEg$@c53K7=m=beeO|(S24S{D*Wx>Ad!^!%MV!wzEYi9ZDyj$5LD??V%h!LQh213 zz-Ver@zo;?E#J7`Kn>hcT<81Z*!9&5QiHnY>4Lnmf>E5prJPpTeUt*@QR*C-^AjFMj+yOamNIAuogKLsSV4j4B%f3V0vzT zerFKlrrxD38B%>EL{DivX^LdZ5u3{Rna2#o!FK-2YPG;f?9L{_)^3HTbr^6BBrWbX#1B4@DEumBW9NBz@XHUX=1e(K|QHkC2-ieSB zM^Ga4X7FPa9)Ke z6kiS45va5rMvHk;i|RCvOore;PtWPVaq$VZa1X0;hNf4yp-_zTpTIWBAfv#8_Sk^7LCPG4DoypLPol;)gne2_8Auhk9KEFPk5{~sr zl1dA7QZL(nG5NPFXW#RCIr$~-KcH0ZRpL_fthsmmNo<}UGkLk|uzR4{LkT-qa#Tk$ zR6LL&BJpYiY4xE|9LXXa@2gdael33M$2iF&){kQV@GwFz&N-T zPUd+ffQ^TBJ3Z1V9Hz#o7lDHm1*DYAL2W z078eBO2x1LHn9X-JxWbg{Hpz!8H#V+90=ALziQ7LyUSyAeRGw_I&|a12_Q@f2_${z zFoPv{S-^04DlAp1l7-kMm3`S+BK2{lVY-kDGQXdI9AAoa5;Nov z`V_Ebe5varP zg@Rdny5IK>rOBQncXM%+v-VqveK7GuM6dQ*q%Xhp!=It1IJlMeFP@pxG-vPWyn{u? zxj6HAJ$mkZz-v};zwQmh4XzyO=6`HNza!mv&@w&&HalbD0y_|7ay!EH}pQXa1 zQ~yMF+RPLN&)e|4TdrQd;;!kG0L$6<*t~0e|HSqoCb{it3)i|w4?~BUaUOzQ!p@}G|)WY5+J&A$c{YOC?bMjXDoUf#b}tGinNK1iZ?GAg=B zSb3kma(4rakJvIJp8beZ7nU!WlDDV+8cXa}y^&4ahL8pBK>^|ma{o){#-eKY06O`g z;81-STqPL@oJH*wS53adm*toN0(COlpkMvY4o=V9^;jS&JY7Q}8;U+jDN}@d76uCn#TKs8-u1^` zzEcwhx^mWkLuWR{4w+}B^_;a<2^(#YmXs6>^o5QPdHWY|pnZ9V+For`Q%VLc7hfd} zy@ik8WcE`^sn(G_b=|~PHg&YGseHA~JIRZ;b#LHxm(H`cw!Y)y=9BeSrHBwFmJGK>+8CQZ)o#U2LEY(&!Y~ZDJt&nb z>L7c8_dha30<~nycW@*hH>CY*Z~D>_6aQ7Qe)c7?V%wpXEEAd`#bqYa&$e?SCHSdI z-E5%P*HpXn(gid5q*(pmUwC2gi!abmegYxv9KBzS*2S|cQ#A8^f-*d5Q&*x1*MH-- z*4o2+Ge>9lFC}=|gDshQ#trAc4xNrp7+2aX?k+sreOj%gVypoD@-7B`7V@RqctTa| z*|F707+5>Y>R&4Vsdk-uTciyLm?i zXZNB!d7nJ4r1cy#JgiLx8iONss?)PE_H}>I;CBpSSLT2DHDMgAAz-&hTK~%T+S`|3 zTyk*JO*+QiZ*zxDA+o1&`4FvC#KmCgzpH5ogvjlaZ8hmy$#?W6u84QkbmzWHL+xEnn>+~KYNhJtqJalgQZpKh#kYB_?z?`?AKl5WL*I%BV)~Pdb3t% z1(W{nCn<1BKJg;%uV7R4pnv5>7Sgb#qH?!Hwtg;H2!Q0tFU%;1NbR6;4M{84jiD;0 z%_$o7QC2!9lVS;>Y_PDv+So+8t@M}L56~Ma>tOcg`52k#!ujCkxqkaC<2JuebB%AU zz6libnyZVOS1+G;Neb|2Y9;;bMLa5i<3A+8rI%e!^@yZz_@g5^biKLN{T}J7f2pZ^ z^8aZ1%CI<^F3K6)g1fsUxI2Ud*Wm8%65I*yG6c6^2_(3?OK^wa?(Q(a_WSKFf9IjA zx~gy0xpq!Bqh_a*lKkw7McvNEBRe&RlZ9A?;#2;c zS8Qv{D_Ps!B?)kPEMbG$d&PiYmzc*g(KJNF!<8#PQo?j^!1C!tyDy(E1VK*jTRioA z+H1IlY>k0lY>-ksC>Hp;zq#R`?@%>5q5?ZJZ~s}q3hIHzE>Q6+TlWe2*c|D7>FB

*aMRBU?7<2Lpx3o4oaty35c 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 T@DC9t5csI6JW?)GG!OhA@x=0& literal 0 HcmV?d00001 diff --git a/doc/assets/system_mode.png b/doc/assets/system_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..165fa3cfaec0e5ca3c7d04816d48aa0cda5778eb GIT binary patch literal 3352 zcmeHK`%}|b7C+xF1OpU#2qG9mTq;w95CkN^ZXqZS8L8CbDsR|QKp>QtMIMHHrLDGT zfGw>Q1VXU|tr!w{x&%n;8m7`fEDHgN5=t=bX8B?zwa3 z+|TEJ{_e3rBLiy#05A$V;`bf^ibE8LdboL&`=52(=w}=W&jv8uu{9B>s@{bMk?i*Z z4*_q0^bB`&lYHOt1rU@Ps{cU%c;i-(pYMrWWcHDuWRJ?KZ?b|RsF^Lvn*Qb9%jqyL zuX3jwOdjRFh3@xK!oSWaoTBF~Ry&U-WfMp|Xm$)QX*H`1Y1#SjGQNA#*{K@s;t_66 zy5eW`zy`~;aVyi`H{73aie#>mnWsV?SHqrt!5*3WNqDTdWZ7qZ+e3nMv7h{#N{C zNV!hkf%P;*EN>#bVtYos9k4j*TDqa)`PZmhA}SpkU9>6Ch9XhaP^>{{(Ak*zoV_2r zN$)9>Qy-eb+mGzArOxQqc*8pG4brC0$W*|X-syX~bv85&GBW+)gJPKOyKWR_D{Dw( zBClMwkDogQGs3PHnD@Es*!HNKRVDzWFW~ec zcy+)+w62fY>EaD#24HdofI&e3&i~;9)3=K5j!RNwn;t)S@L=1$=QXvpWXVka4~RZE z{n(wy3U7McmMSBg-&}by*3!ZCX6*-$w<2GwE51I(_%qYjq-*{x)c;YTww}l?*XEVt z;lFx%uB8d`8ygz~3ES+Tli25PILP&(QOcG7Tq8@=j4c zE3$PjbQvK5X`(8*!$ScuuK_O!yzn818YTYuoWtT?xRuziQ^P zyt(3k)DF5UQ8<+lRj}+IX$Klyew3!<`I?9lMrF5GLU2W*;n<4;2^o2Xv8^kK0>VZ_ z;iof?(9SUK&oegu1?|wDz$C~Wu}cElHLU~}Y}9zisZU8Fe>^YE`>w&zK9w6|Y@pza zZP}%lwggsfw5K_dG{Wtdu(L_1ykWt2&rppLUHwS>O>f90i7AY?IhcalOZilrDF{O2 z#&Z_EDrMUU^C{xd3A)xOo9KM^;^KO}IuYjk#pQm=&+DTF$tb1oME?-7r6gI@()HO( zl0|by2@V(J4j9+k=cQ7nDe}-MQ>_Vms$?B)!UNJP;2f~Yu9hXWMcESff(xflcTV=( z1`@O9jXUCwO~J&Rm6kC8&cj)Z`A*EdD}uZ*ZXu{f;$r*1;R runApp(const DemoApp()); + +class DemoApp extends StatelessWidget { + const DemoApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ZdsApp( + title: 'zds_flutter Demo', + routes: kAllRoutes, // To use built in router from Material package + home: HomeWidget(), // To use another router + zetaColors: ZetaColors(...), // Optional: To use theme from zeta_flutter package + ); + } +} +``` diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 66320a6..296293a 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,7 +1,6 @@ PODS: - - connectivity_plus (0.0.1): + - device_info_plus (0.0.1): - Flutter - - ReachabilitySwift - DKImagePickerController/Core (4.3.4): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource @@ -37,7 +36,7 @@ PODS: - DKImagePickerController/PhotoGallery - Flutter - Flutter (1.0.0) - - flutter_image_compress (1.0.0): + - flutter_image_compress_common (1.0.0): - Flutter - Mantle - SDWebImage @@ -51,16 +50,9 @@ PODS: - OrderedSet (~> 5.0) - flutter_keyboard_visibility (0.0.1): - Flutter - - fluttertoast (0.0.2): - - Flutter - - Toast - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - image_compression_flutter (1.0.0): - - Flutter - - image_editor_common (1.0.0): - - Flutter - image_picker_ios (0.0.1): - Flutter - libwebp (1.3.1): @@ -78,17 +70,16 @@ PODS: - Mantle (2.2.0): - Mantle/extobjc (= 2.2.0) - Mantle/extobjc (2.2.0) - - nb_utils (0.0.1): - - Flutter - open_filex (0.0.2): - Flutter - OrderedSet (5.0.0) + - package_info_plus (0.4.5): + - Flutter + - pasteboard (0.0.1): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - - permission_handler_apple (9.1.1): - - Flutter - - ReachabilitySwift (5.0.0) - SDWebImage (5.17.0): - SDWebImage/Core (= 5.17.0) - SDWebImage/Core (5.17.0) @@ -102,34 +93,34 @@ PODS: - Flutter - FMDB (>= 2.7.5) - SwiftyGif (5.4.4) - - Toast (4.0.0) - url_launcher_ios (0.0.1): - Flutter - video_compress (0.3.0): - Flutter - - webview_flutter_wkwebview (0.0.1): + - video_player_avfoundation (0.0.1): + - Flutter + - FlutterMacOS + - wakelock_plus (0.0.1): - Flutter DEPENDENCIES: - - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) - - flutter_image_compress (from `.symlinks/plugins/flutter_image_compress/ios`) + - flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`) - flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`) - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) - - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - - image_compression_flutter (from `.symlinks/plugins/image_compression_flutter/ios`) - - image_editor_common (from `.symlinks/plugins/image_editor_common/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - - nb_utils (from `.symlinks/plugins/nb_utils/ios`) - open_filex (from `.symlinks/plugins/open_filex/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - pasteboard (from `.symlinks/plugins/pasteboard/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_compress (from `.symlinks/plugins/video_compress/ios`) - - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) + - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) + - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) SPEC REPOS: trunk: @@ -139,41 +130,33 @@ SPEC REPOS: - libwebp - Mantle - OrderedSet - - ReachabilitySwift - SDWebImage - SDWebImageWebPCoder - SwiftyGif - - Toast EXTERNAL SOURCES: - connectivity_plus: - :path: ".symlinks/plugins/connectivity_plus/ios" + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter - flutter_image_compress: - :path: ".symlinks/plugins/flutter_image_compress/ios" + flutter_image_compress_common: + :path: ".symlinks/plugins/flutter_image_compress_common/ios" flutter_inappwebview: :path: ".symlinks/plugins/flutter_inappwebview/ios" flutter_keyboard_visibility: :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" - fluttertoast: - :path: ".symlinks/plugins/fluttertoast/ios" - image_compression_flutter: - :path: ".symlinks/plugins/image_compression_flutter/ios" - image_editor_common: - :path: ".symlinks/plugins/image_editor_common/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" - nb_utils: - :path: ".symlinks/plugins/nb_utils/ios" open_filex: :path: ".symlinks/plugins/open_filex/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" + pasteboard: + :path: ".symlinks/plugins/pasteboard/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" - permission_handler_apple: - :path: ".symlinks/plugins/permission_handler_apple/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" sqflite: @@ -182,41 +165,39 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher_ios/ios" video_compress: :path: ".symlinks/plugins/video_compress/ios" - webview_flutter_wkwebview: - :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" + video_player_avfoundation: + :path: ".symlinks/plugins/video_player_avfoundation/darwin" + wakelock_plus: + :path: ".symlinks/plugins/wakelock_plus/ios" SPEC CHECKSUMS: - connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e + device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: ce3938a0df3cc1ef404671531facef740d03f920 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - flutter_image_compress: 5a5e9aee05b6553048b8df1c3bc456d0afaac433 - flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721 + flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e + flutter_inappwebview: 3d32228f1304635e7c028b0d4252937730bbc6cf flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 - fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - image_compression_flutter: 5327fc5ee43f5ee6107d44ff0d4480a363788358 - image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43 image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 libwebp: 33dc822fbbf4503668d09f7885bbfedc76c45e96 Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d - nb_utils: ada4338858d8827ec92fdab2a545206b4ba4cfb1 open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4 OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c + package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 + pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 - permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 - ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9 SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102 shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f - Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 - url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 + url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe - webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f + video_player_avfoundation: e9e6f9cae7d7a6d9b43519b0aab382bca60fcfd1 + wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 PODFILE CHECKSUM: ef2759a31e8883d6b534c00ef22a7f4104f8de0d -COCOAPODS: 1.12.1 +COCOAPODS: 1.14.3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 9f93cb7..b889b53 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -155,7 +155,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -204,6 +204,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a..a6b826d 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - PreviewsEnabled - - - diff --git a/example/lib/home.dart b/example/lib/home.dart index af355be..8f8205e 100644 --- a/example/lib/home.dart +++ b/example/lib/home.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; - import 'package:zds_flutter/zds_flutter.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; +import 'package:zds_flutter_example/pages/utils/theme_color_switch.dart'; +import 'package:zds_flutter_example/pages/utils/theme_constrast_switch.dart'; +import 'package:zds_flutter_example/pages/utils/theme_mode_switch.dart'; import 'routes.dart'; @@ -12,102 +13,50 @@ class HomePage extends StatefulWidget { State createState() => _HomePageState(); } -final Map colorMap = { - 'Red': ZetaColorBase.red, - 'Orange': ZetaColorBase.orange, - 'Yellow': ZetaColorBase.yellow, - 'Green': ZetaColorBase.green, - 'Blue': ZetaColorBase.blue, - 'Teal': ZetaColorBase.teal, - 'Pink': ZetaColorBase.pink, -}; - -const String _darkModeKey = 'dark'; - class _HomePageState extends State { - GlobalKey key = GlobalKey(); - @override Widget build(BuildContext _) { - return Builder(builder: (context) { - return Scaffold( - appBar: AppBar( - title: const Text('ZDS_Flutter Demo'), - centerTitle: true, - actions: [ - ZdsPopupMenu( - onSelected: (dynamic val) { - if (val is ZetaColorSwatch) { - ZetaColors.setColors(context, ZetaColors(primary: val, secondary: val)); - } else if (val is String && val == _darkModeKey) { - ZetaColors.setDarkMode(context, !ZetaColors.of(context).isDarkMode); - } - setState(() { - key = GlobalKey(); - }); - }, - builder: (_, open) => IconButton( - splashRadius: 20, - visualDensity: VisualDensity.compact, - onPressed: open, - icon: const Icon(ZdsIcons.more_vert), - ), - items: [ - ...colorMap.entries - .map( - (e) => ZdsPopupMenuItem( - value: e.value, - child: ListTile( - visualDensity: VisualDensity.compact, - title: Text(e.key), - ), - ), - ) - .toList(), - ZdsPopupMenuItem( - value: _darkModeKey, - child: ListTile( - visualDensity: VisualDensity.compact, - title: Text(ZetaColors.of(context).isDarkMode ? 'Light mode' : 'Dark mode'), + final zeta = Zeta.of(context); + return Scaffold( + appBar: AppBar( + leadingWidth: 20, + leading: SizedBox(width: 20), + title: const Text('ZDS Demo'), + centerTitle: false, + actions: [ + ZetaThemeModeSwitch(), + ZetaThemeContrastSwitch(), + ZetaThemeColorSwitch(), + ], + ), + body: ZdsList.builder( + padding: const EdgeInsets.symmetric(vertical: 14), + itemCount: kRoutes.length, + itemBuilder: (context, index) { + final rec = kRoutes.entries.toList()[index]; + final items = rec.value..sort((a, b) => a.title.compareTo(b.title)); + + return ZdsExpansionTile( + title: Text( + rec.key, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: zeta.colors.textDefault, ), - ), - ], ), - ], - ), - body: Builder( - key: key, - builder: (context) { - print('BUILDERING'); - return ZdsList.builder( - padding: const EdgeInsets.symmetric(vertical: 14), - itemCount: kRoutes.length, - itemBuilder: (context, index) { - final rec = kRoutes.entries.toList()[index]; - final items = rec.value..sort((a, b) => a.title.compareTo(b.title)); - return ZdsExpansionTile( - title: Text( - rec.key, - style: Theme.of(context).textTheme.titleMedium?.copyWith( - color: ZetaColors.of(context).textDefault, - ), + child: ZdsListGroup( + items: items.map((route) { + return ZdsListTile( + title: Text(route.title), + trailing: Icon( + Icons.keyboard_arrow_right, + color: zeta.colors.iconSubtle, ), - child: ZdsListGroup( - items: items.map((route) { - return ZdsListTile( - title: Text(route.title), - trailing: Icon( - Icons.keyboard_arrow_right, - color: ZetaColors.of(context).textDefault, - ), - onTap: () => Navigator.of(context).pushNamed(route.routeName)); - }).toList(), - ).space(14), - ); - }, - ); - }), - ); - }); + onTap: () => Navigator.of(context).pushNamed(route.routeName)); + }).toList(), + ).space(14), + ); + }, + ), + ); } } diff --git a/example/lib/main.dart b/example/lib/main.dart index 3c8b3cf..ffd6d8f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,18 +1,68 @@ import 'package:flutter/material.dart'; import 'package:zds_flutter/zds_flutter.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'routes.dart'; -void main() => runApp(const DemoApp()); +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + final preferences = await SharedPreferences.getInstance(); + final themeService = ZdsThemeService(assetPath: 'assets/colors.json', preferences: preferences); + final themeData = await themeService.load(); + runApp( + DemoApp( + data: themeData, + themeService: themeService, + ), + ); +} class DemoApp extends StatelessWidget { - const DemoApp({Key? key}) : super(key: key); + const DemoApp({Key? key, required this.data, required this.themeService}) : super(key: key); + + final ZetaThemeService themeService; + final ZdsThemeData data; @override Widget build(BuildContext context) { - return ZdsApp( - title: 'zds_flutter Demo', - routes: kAllRoutes, + return ZetaProvider( + themeService: themeService, + initialThemeMode: data.themeMode, + initialThemeData: data.themeData, + initialContrast: data.contrast, + builder: (context, themeData, themeMode) { + return MaterialApp( + title: 'Zds Demo', + localeResolutionCallback: (Locale? locale, Iterable supportedLocales) { + return locale != null && ComponentStrings.delegate.isSupported(locale) + ? locale + : ComponentStrings.defaultLocale; + }, + builder: (BuildContext context, Widget? child) { + return ZdsBottomBarTheme( + data: buildZdsBottomBarThemeData(context), + child: child ?? const SizedBox(), + ); + }, + localizationsDelegates: >[ + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ComponentStrings.delegate, + ], + routes: kAllRoutes, + themeMode: themeMode, + theme: themeData.colorsLight.toScheme().toTheme( + fontFamily: themeData.fontFamily, + appBarStyle: data.lightAppBarStyle, + ), + darkTheme: themeData.colorsDark.toScheme().toTheme( + fontFamily: themeData.fontFamily, + appBarStyle: data.darkAppBarStyle, + ), + ); + }, ); } } diff --git a/example/lib/pages/assets/icons.dart b/example/lib/pages/assets/icons.dart index acb6666..242b176 100644 --- a/example/lib/pages/assets/icons.dart +++ b/example/lib/pages/assets/icons.dart @@ -1,5 +1,5 @@ +import 'dart:async'; import 'dart:convert'; -import 'dart:core'; import 'package:flutter/material.dart'; import 'package:zds_flutter/zds_flutter.dart'; @@ -17,12 +17,12 @@ class _IconsDemoState extends State { Future>> getData(BuildContext context) async { final List> icons = []; final data = jsonDecode( - await DefaultAssetBundle.of(context).loadString('packages/zds_flutter/lib/assets/fonts/selection.json'), + await DefaultAssetBundle.of(context).loadString('packages/$packageName/lib/assets/fonts/selection.json'), )['icons']; for (final e in data) { icons.add({ 'ZdsIcons.${e['properties']['name']}': - IconData(e['properties']['code'], fontFamily: 'zds-icons', fontPackage: 'zds_flutter') + IconData(e['properties']['code'], fontFamily: 'zds-icons', fontPackage: packageName) }); keys.add(GlobalKey()); } @@ -38,28 +38,26 @@ class _IconsDemoState extends State { if (future.connectionState == ConnectionState.done && future.data != null) { final List> icons = future.data as List>; return GridView.count( - crossAxisCount: (MediaQuery.of(context).size.width / 100).floor(), - padding: const EdgeInsets.symmetric(vertical: 32), - children: [ - ...icons.map((e) { - return Column( - children: [ - Icon( - e.values.first, - color: ZdsColors.darkGrey, - size: 48, - ).withPopOver( - (context) => Container( - constraints: const BoxConstraints(maxHeight: 300, maxWidth: 300), - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 25), - child: Text(e.keys.first), - ), - ) - ], - ); - }).toList() - ], - ); + crossAxisCount: (MediaQuery.of(context).size.width / 100).floor(), + padding: const EdgeInsets.symmetric(vertical: 32), + children: [ + ...icons.map((e) { + return Column( + children: [ + Icon( + e.values.first, + size: 48, + ).withPopOver( + (context) => Container( + constraints: const BoxConstraints(maxHeight: 300, maxWidth: 300), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 25), + child: Text(e.keys.first), + ), + ) + ], + ); + }).toList() + ]); } else { return const Center(child: CircularProgressIndicator()); } diff --git a/example/lib/pages/assets/images.dart b/example/lib/pages/assets/images.dart index bf9a3c9..e27fe37 100644 --- a/example/lib/pages/assets/images.dart +++ b/example/lib/pages/assets/images.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class ImagesDemo extends StatelessWidget { @@ -8,60 +9,84 @@ class ImagesDemo extends StatelessWidget { Widget build(BuildContext context) { final List images = [ { - 'name': 'ZdsImages.notifications', - 'image': ZdsImages.notifications, + 'name': 'ZdsImages.calendar', + 'image': ZdsImages.calendar, }, { 'name': 'ZdsImages.chat', 'image': ZdsImages.chat, }, { - 'name': 'ZdsImages.notes', - 'image': ZdsImages.notes, + 'name': 'ZdsImages.clock', + 'image': ZdsImages.clock, }, { - 'name': 'ZdsImages.calendar', - 'image': ZdsImages.calendar, + 'name': 'ZdsImages.cloudFail', + 'image': ZdsImages.cloudFail, }, { 'name': 'ZdsImages.completedTasks', 'image': ZdsImages.completedTasks, }, { - 'name': 'ZdsImages.emptyBox', - 'image': ZdsImages.emptyBox, + 'name': 'ZdsImages.darkMode', + 'image': ZdsImages.darkMode, }, { - 'name': 'ZdsImages.sadZebra', - 'image': ZdsImages.sadZebra, + 'name': 'ZdsImages.emptyBox', + 'image': ZdsImages.emptyBox, }, { - 'name': 'ZdsImages.sleepingZebra', - 'image': ZdsImages.sleepingZebra, + 'name': 'ZdsImages.internetFail', + 'image': ZdsImages.internetFail, }, { - 'name': 'ZdsImages.search', - 'image': ZdsImages.search, + 'name': 'ZdsImages.lightMode', + 'image': ZdsImages.lightMode, }, { 'name': 'ZdsImages.loadFail', 'image': ZdsImages.loadFail, }, { - 'name': 'ZdsImages.cloudFail', - 'image': ZdsImages.cloudFail, + 'name': 'ZdsImages.map', + 'image': ZdsImages.map, + }, + { + 'name': 'ZdsImages.lightMode', + 'image': ZdsImages.lightMode, + }, + { + 'name': 'ZdsImages.darkMode', + 'image': ZdsImages.darkMode, + }, + { + 'name': 'ZdsImages.notes', + 'image': ZdsImages.notes, + }, + { + 'name': 'ZdsImages.notifications', + 'image': ZdsImages.notifications, + }, + { + 'name': 'ZdsImages.sadZebra', + 'image': ZdsImages.sadZebra, + }, + { + 'name': 'ZdsImages.search', + 'image': ZdsImages.search, }, { 'name': 'ZdsImages.serverFail', 'image': ZdsImages.serverFail, }, { - 'name': 'ZdsImages.punch', - 'image': ZdsImages.punch, + 'name': 'ZdsImages.sleepingZebra', + 'image': ZdsImages.sleepingZebra, }, { - 'name': 'ZdsImages.map', - 'image': ZdsImages.map, + 'name': 'ZdsImages.systemMode', + 'image': ZdsImages.systemMode, }, ]; @@ -84,18 +109,15 @@ class ImagesDemo extends StatelessWidget { class ImgBox extends StatelessWidget { final Widget img; final String name; - const ImgBox({Key? key, required this.img, required this.name}) : super(key: key); @override Widget build(BuildContext context) { - return Column( - children: [ - img, - const SizedBox(height: 12), - Text(name), - const SizedBox(height: 32), - ], - ); + return Column(children: [ + img, + const SizedBox(height: 12), + Text(name), + const SizedBox(height: 32), + ]); } } diff --git a/example/lib/pages/components/app_bar.dart b/example/lib/pages/components/app_bar.dart index 528d228..c77bde4 100644 --- a/example/lib/pages/components/app_bar.dart +++ b/example/lib/pages/components/app_bar.dart @@ -19,75 +19,86 @@ class _AppBarDemoState extends State with SingleTickerProviderStateM @override void dispose() { - controller!.dispose(); + controller?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { - final tabs = ZdsTabBar( - controller: controller, - tabs: const [ - ZdsTab( - icon: Icon(ZdsIcons.details), - label: 'Details', - ), - ZdsTab( - icon: Icon(ZdsIcons.edit), - label: 'Edit', - ), - ZdsTab( - icon: Icon(ZdsIcons.delete), - label: 'Discard', - ), - ZdsTab( - icon: Icon(ZdsIcons.unclaim), - label: 'Unclaim', - ), - ZdsTab( - icon: Icon(ZdsIcons.history), - label: 'History', - ), - ], - ); + final themeData = Theme.of(context); + final zetaColors = Zeta.of(context).colors; + + ZdsTabBar tabs(ZdsTabBarColor color, [bool topSafeArea = true, bool bottomSafeArea = false]) { + return ZdsTabBar( + controller: controller, + color: color, + topSafeArea: topSafeArea, + bottomSafeArea: bottomSafeArea, + tabs: const [ + ZdsTab( + icon: Icon(ZdsIcons.details), + label: 'Details', + ), + ZdsTab( + icon: Icon(ZdsIcons.edit), + label: 'Edit', + ), + ZdsTab( + icon: Icon(ZdsIcons.delete), + label: 'Discard', + ), + ZdsTab( + icon: Icon(ZdsIcons.unclaim), + label: 'Unclaim', + ), + ZdsTab( + icon: Icon(ZdsIcons.history), + label: 'History', + ), + ], + ); + } + final actions = [ IconButton( onPressed: () {}, icon: const Icon(ZdsIcons.edit), ), ]; + return Scaffold( + appBar: ZdsAppBar( + title: const Text('Primary color scheme'), + subtitle: const Text('Subtitle!'), + icon: CircleAvatar( + radius: 15, + backgroundColor: themeData.appBarTheme.foregroundColor, + child: Text( + 'DM', + style: TextStyle( + color: themeData.colorScheme.primaryContainer, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + actions: actions, + bottom: tabs(ZdsTabBarColor.appBar), + ), body: SingleChildScrollView( child: Column( children: [ ZdsAppBar( - title: const Text('Primary color scheme'), - subtitle: const Text('Subtitle!'), - icon: CircleAvatar( - radius: 15, - backgroundColor: ZdsColors.white, - child: Text( - 'DM', - style: TextStyle( - color: Theme.of(context).colorScheme.primaryContainer, - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ), - actions: actions, - bottom: tabs, - ), - ZdsAppBar( + applyTopSafeArea: false, color: ZdsTabBarColor.basic, title: const Text('Basic color scheme'), icon: CircleAvatar( radius: 15, - backgroundColor: ZdsColors.white, + backgroundColor: zetaColors.iconInverse, child: Text( 'DM', style: TextStyle( - color: Theme.of(context).colorScheme.primaryContainer, + color: themeData.colorScheme.primaryContainer, fontSize: 12, fontWeight: FontWeight.bold, ), @@ -95,26 +106,27 @@ class _AppBarDemoState extends State with SingleTickerProviderStateM ), subtitle: const Text('Subtitle!'), actions: actions, - bottom: tabs, + bottom: tabs(ZdsTabBarColor.basic, false, false), ), ZdsAppBar( + applyTopSafeArea: false, title: const Text('Surface color scheme'), subtitle: const Text('Subtitle!'), color: ZdsTabBarColor.surface, icon: CircleAvatar( radius: 15, - backgroundColor: ZdsColors.white, + backgroundColor: zetaColors.secondary, child: Text( 'DM', style: TextStyle( - color: Theme.of(context).colorScheme.primaryContainer, + color: themeData.colorScheme.onSecondary, fontSize: 12, fontWeight: FontWeight.bold, ), ), ), actions: actions, - bottom: tabs, + bottom: tabs(ZdsTabBarColor.surface, false, false), ), ].divide(const SizedBox(height: 40)).toList(), ), diff --git a/example/lib/pages/components/big_toggle_button.dart b/example/lib/pages/components/big_toggle_button.dart index 6311d7d..378c412 100644 --- a/example/lib/pages/components/big_toggle_button.dart +++ b/example/lib/pages/components/big_toggle_button.dart @@ -12,7 +12,7 @@ class _BigToggleButtonDemoState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: Column( + body: ZdsList( children: [ ZdsToggleButton( values: const ['A', 'B', 'C', 'D'], diff --git a/example/lib/pages/components/block_table.dart b/example/lib/pages/components/block_table.dart index 3ffcbb7..0d634e8 100644 --- a/example/lib/pages/components/block_table.dart +++ b/example/lib/pages/components/block_table.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class BlockTableDemo extends StatelessWidget { diff --git a/example/lib/pages/components/bottom_bar.dart b/example/lib/pages/components/bottom_bar.dart index a32a3a4..c70f0bc 100644 --- a/example/lib/pages/components/bottom_bar.dart +++ b/example/lib/pages/components/bottom_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class BottomBarDemo extends StatelessWidget { diff --git a/example/lib/pages/components/bottom_sheet.dart b/example/lib/pages/components/bottom_sheet.dart index 28b13f9..fd5e104 100644 --- a/example/lib/pages/components/bottom_sheet.dart +++ b/example/lib/pages/components/bottom_sheet.dart @@ -28,8 +28,7 @@ class _BottomSheetDemoState extends State with SingleTickerProv Widget build(BuildContext context) { return SizedBox( width: double.infinity, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, + child: ZdsList( children: [ ZdsButton( onTap: bottomSheetUsingBuildSheetBars, @@ -49,7 +48,7 @@ class _BottomSheetDemoState extends State with SingleTickerProv ), ZdsButton.muted( onTap: showBottomSheet3, - child: const Text('Show bottomsheet 5 items'), + child: const Text('Show bottom sheet 5 items'), ), ].divide(const SizedBox(height: 20)).toList(), ), @@ -74,11 +73,14 @@ class _BottomSheetDemoState extends State with SingleTickerProv ), ], ), - ZdsListTile( - title: const Text('Favorite'), - trailing: Switch( - onChanged: (v) {}, - value: true, + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + title: const Text('Favorite'), + trailing: Switch( + onChanged: (v) {}, + value: true, + ), ), ), ZdsListGroup( @@ -186,6 +188,7 @@ class _BottomSheetDemoState extends State with SingleTickerProv showZdsBottomSheet( context: context, headerBuilder: (context) => ZdsTabBar( + color: ZdsTabBarColor.surface, controller: controller, tabs: const [ ZdsTab( @@ -199,7 +202,7 @@ class _BottomSheetDemoState extends State with SingleTickerProv bottomBuilder: (context) => ZdsBottomBar( child: Row( children: [ - ZdsButton.outlined( + ZdsButton.text( child: const Text('Save'), onTap: () { Navigator.of(context).pop(); @@ -234,23 +237,23 @@ class _BottomSheetDemoState extends State with SingleTickerProv showZdsBottomSheet( enforceSheet: enforceSheet, context: context, + headerBuilder: (context) => ZdsSheetHeader(headerText: 'Select Priority'), builder: (context) { return Column( mainAxisSize: MainAxisSize.min, children: [ - const Text('Select priority').textStyle(Theme.of(context).textTheme.headlineSmall).paddingOnly(bottom: 20), ZdsListTile( - leading: const Text('Urgent'), + leading: Text('Urgent'), trailing: ZdsIndex( - color: ZdsColors.red, - child: const Text('U'), + color: Zeta.of(context).colors.red, + child: Text('U'), ), ), ZdsListTile( - leading: const Text('Hight'), + leading: Text('Height'), trailing: ZdsIndex( - color: ZdsColors.orange, - child: const Text('1'), + color: Zeta.of(context).colors.orange, + child: Text('1'), ), ), ZdsListTile( @@ -261,10 +264,10 @@ class _BottomSheetDemoState extends State with SingleTickerProv ), ), ZdsListTile( - leading: const Text('Low'), + leading: Text('Low'), trailing: ZdsIndex( - color: ZdsColors.green, - child: const Text('3'), + color: Zeta.of(context).colors.green, + child: Text('3'), ), ), ], @@ -291,66 +294,70 @@ class _BottomSheetDemoState extends State with SingleTickerProv showZdsBottomSheet( context: context, bottomInset: 0, - builder: (context) => ListView( - shrinkWrap: true, - children: [ - Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ExcludeSemantics( - child: Text( - 'Date range', - style: Theme.of(context).textTheme.titleSmall!.copyWith(color: ZdsColors.greySwatch(context)[1000]), - ).paddingOnly(left: 8), - ), - const SizedBox(height: 8), - ZdsDateRangePickerTile( - initialDateController: fromDateController, - finalDateController: toDateController, - ), - const SizedBox(height: 8), - Row( - children: [ - ExcludeSemantics( - child: Text( - 'Type', - style: Theme.of(context).textTheme.titleSmall!.copyWith( - color: ZdsColors.greySwatch(context)[1000], - ), - ).paddingOnly(left: 8), - ), - const Spacer(), - ], - ), - const SizedBox(height: 8), - ZdsListGroup( - padding: EdgeInsets.zero, - items: [ - Semantics( - checked: isDayOff, - child: ZdsListTile( - title: const Text('Day off'), - onTap: () {}, - trailing: Icon(ZdsIcons.check, color: Theme.of(context).colorScheme.secondary), + builder: (context) { + final zetaColors = Zeta.of(context).colors; + final themeData = Theme.of(context); + return ListView( + shrinkWrap: true, + children: [ + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ExcludeSemantics( + child: Text( + 'Date range', + style: themeData.textTheme.titleSmall?.copyWith(color: zetaColors.textSubtle), + ).paddingOnly(left: 8), + ), + const SizedBox(height: 8), + ZdsDateRangePickerTile( + initialDateController: fromDateController, + finalDateController: toDateController, + ), + const SizedBox(height: 8), + Row( + children: [ + ExcludeSemantics( + child: Text( + 'Type', + style: themeData.textTheme.titleSmall?.copyWith( + color: zetaColors.textSubtle, + ), + ).paddingOnly(left: 8), + ), + const Spacer(), + ], + ), + const SizedBox(height: 8), + ZdsListGroup( + padding: EdgeInsets.zero, + items: [ + Semantics( + checked: isDayOff, + child: ZdsListTile( + title: const Text('Day off'), + onTap: () {}, + trailing: Icon(ZdsIcons.check, color: themeData.colorScheme.secondary), + ), ), - ), - Semantics( - checked: isDayOff, - child: ZdsListTile( - title: const Text('Time off'), - onTap: () {}, + Semantics( + checked: isDayOff, + child: ZdsListTile( + title: const Text('Time off'), + onTap: () {}, + ), ), - ), - ], - ), - ], - ).paddingOnly(left: 16, right: 16, top: 12), - ), - const SizedBox(height: 16), - ], - ), + ], + ), + ], + ).paddingOnly(left: 16, right: 16, top: 12), + ), + const SizedBox(height: 16), + ], + ); + }, headerBuilder: (context) => sheetBarWidgets[0] as PreferredSizeWidget, bottomBuilder: (context) => sheetBarWidgets.asMap().containsKey(1) ? sheetBarWidgets[1] as PreferredSizeWidget : null, @@ -368,6 +375,7 @@ class _BottomSheetDemoState extends State with SingleTickerProv ternaryActionOnTap: () {}, showClose: true, ); + final ZdsValueController fromDateController = ZdsValueController(); final ZdsValueController toDateController = ZdsValueController(); const bool isDayOff = false; @@ -376,11 +384,12 @@ class _BottomSheetDemoState extends State with SingleTickerProv context: context, bottomInset: 0, maxHeight: 440, + backgroundColor: Theme.of(context).colorScheme.surface, builder: (context) => Column( children: [ sheetBarWidgets[0], Expanded( - child: Center( + child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, @@ -388,8 +397,9 @@ class _BottomSheetDemoState extends State with SingleTickerProv ExcludeSemantics( child: Text( 'Date range', - style: - Theme.of(context).textTheme.titleSmall!.copyWith(color: ZdsColors.greySwatch(context)[1000]), + style: Theme.of(context).textTheme.titleSmall?.copyWith( + color: Zeta.of(context).colors.textSubtle, + ), ).paddingOnly(left: 10), ), const SizedBox(height: 8), @@ -403,8 +413,8 @@ class _BottomSheetDemoState extends State with SingleTickerProv ExcludeSemantics( child: Text( 'Type', - style: Theme.of(context).textTheme.titleSmall!.copyWith( - color: ZdsColors.greySwatch(context)[1000], + style: Theme.of(context).textTheme.titleSmall?.copyWith( + color: Zeta.of(context).colors.textSubtle, ), ).paddingOnly(left: 10), ), diff --git a/example/lib/pages/components/bottom_tab_bar.dart b/example/lib/pages/components/bottom_tab_bar.dart index f664735..c450495 100644 --- a/example/lib/pages/components/bottom_tab_bar.dart +++ b/example/lib/pages/components/bottom_tab_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class BottomTabBarDemo extends StatefulWidget { @@ -71,27 +72,24 @@ class _BottomTabBarDemoState extends State { onTap: (index) => setState(() => currentIndex = index), items: const [ ZdsNavItem( - icon: IconWithBadge( - Icons.article_outlined, - unread: 4, - semanticsLabel: '4 unread forms', - ), - label: 'Forms', - ), + icon: IconWithBadge( + Icons.article_outlined, + unread: 4, + semanticsLabel: '4 unread forms', + ), + label: 'Forms'), ZdsNavItem( - icon: IconWithBadge( - Icons.search, - ), - label: 'Search', - ), + icon: IconWithBadge( + Icons.search, + ), + label: 'Search'), ZdsNavItem( - icon: IconWithBadge( - Icons.analytics_outlined, - unread: 50000, - maximumDigits: 4, - ), - label: 'Reports', - ), + icon: IconWithBadge( + Icons.analytics_outlined, + unread: 50000, + maximumDigits: 4, + ), + label: 'Reports'), ], ), ); diff --git a/example/lib/pages/components/button.dart b/example/lib/pages/components/button.dart index 823e875..2e27059 100644 --- a/example/lib/pages/components/button.dart +++ b/example/lib/pages/components/button.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:zds_flutter/zds_flutter.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; class ButtonDemo extends StatefulWidget { const ButtonDemo({Key? key}) : super(key: key); @@ -115,32 +116,33 @@ class _ButtonDemoState extends State { child: const Text('Muted'), ), ], - // Row( - // children: [ - // Expanded( - // child: SingleChildScrollView( - // scrollDirection: Axis.horizontal, - // child: Row( - // children: [ - // const SizedBox(width: 24), - // ...ZetaColors.of(context) - // .rainbow - // .map( - // (e) => ZdsButton.filled( - // onTap: () {}, - // color: e, - // child: const Text('Button'), - // ), - // ) - // .divide(const SizedBox(width: 16)) - // .toList(), - // const SizedBox(width: 24), - // ], - // ), - // ), - // ) - // ], - // ).paddingInsets(const EdgeInsets.symmetric(vertical: 24)), + Row( + children: [ + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + const SizedBox(width: 24), + ...Zeta.of(context) + .colors + .rainbow + .map( + (e) => ZdsButton.filled( + onTap: () {}, + customColor: e, + child: const Text('Button'), + ), + ) + .divide(const SizedBox(width: 16)) + .toList(), + const SizedBox(width: 24), + ], + ), + ), + ) + ], + ).paddingInsets(const EdgeInsets.symmetric(vertical: 24)), Align( alignment: Alignment.centerRight, child: ZdsPopupMenu( @@ -148,7 +150,7 @@ class _ButtonDemoState extends State { splashRadius: 20, visualDensity: VisualDensity.compact, onPressed: open, - color: ZdsColors.greySwatch(context)[800], + color: Zeta.of(context).colors.iconSubtle, icon: const Icon(ZdsIcons.more_vert), ), items: const [ @@ -199,15 +201,15 @@ class _ButtonDemoState extends State { onTap: () => setState(() => isButtonSelected = !isButtonSelected), leadingIcon: const Icon(ZdsIcons.person_info), onClose: () {}, - // color: ZetaColorBase.green, ), ZdsSelectionPill( selected: !isButtonSelected, label: 'Approved', + leadingIcon: const Icon(ZdsIcons.person_info), onTap: () => setState(() => isButtonSelected = !isButtonSelected), onClose: () {}, ), - const ZdsSelectionPill( + ZdsSelectionPill( selected: true, label: 'Pending', ), @@ -235,9 +237,9 @@ class _ButtonDemoState extends State { ), const SizedBox(height: 12), ZdsSlidableButton( - buttonColor: ZdsColors.greyWarmSwatch.shade900, + buttonColor: Zeta.of(context).colors.iconDefault, buttonText: 'Clock Out', - buttonSliderColor: ZdsColors.greyWarmSwatch.shade200, + buttonSliderColor: Zeta.of(context).colors.warm.surface, buttonIcon: ZdsIcons.clock_stop, ), const SizedBox(height: 36), @@ -266,10 +268,10 @@ class _ButtonDemoState extends State { Text('Active, basic without animation', style: Theme.of(context).textTheme.headlineMedium), const SizedBox(height: 12), ZdsSlidableButton( - buttonColor: ZdsColors.greyWarmSwatch.shade900, + buttonColor: Zeta.of(context).colors.iconDefault, buttonText: 'Clock Out', buttonIcon: ZdsIcons.clock_stop, - buttonSliderColor: ZdsColors.greyWarmSwatch.shade200, + buttonSliderColor: Zeta.of(context).colors.warm.surface, onSlideComplete: () async { debugPrint('Done!'); return true; @@ -282,13 +284,13 @@ class _ButtonDemoState extends State { ), const SizedBox(height: 12), ZdsSlidableButton( - buttonColor: ZdsColors.greyWarmSwatch.shade900, + buttonColor: Zeta.of(context).colors.iconDefault, buttonColorEnd: Theme.of(context).colorScheme.secondary, buttonText: 'Clock Out', buttonTextEnd: DateTime.now().format('KK:mm a'), buttonIcon: ZdsIcons.clock_stop, buttonIconEnd: ZdsIcons.check_circle, - buttonSliderColor: ZdsColors.greyWarmSwatch.shade200, + buttonSliderColor: Zeta.of(context).colors.warm.surface, buttonSliderColorEnd: Theme.of(context).primaryColorLight, onSlideComplete: () async { debugPrint('Done!'); @@ -300,19 +302,19 @@ class _ButtonDemoState extends State { Text('Disabled, no message', style: Theme.of(context).textTheme.headlineMedium), const SizedBox(height: 12), ZdsSlidableButton( - buttonColor: ZdsColors.greyWarmSwatch.shade900, + buttonColor: Zeta.of(context).colors.iconDefault, buttonText: 'Clock Out', buttonIcon: ZdsIcons.clock_stop, - buttonSliderColor: ZdsColors.greyWarmSwatch.shade200, + buttonSliderColor: Zeta.of(context).colors.warm.surface, ), const SizedBox(height: 36), Text('Disabled with message', style: Theme.of(context).textTheme.headlineMedium), const SizedBox(height: 12), ZdsSlidableButton( - buttonColor: ZdsColors.greyWarmSwatch.shade900, + buttonColor: Zeta.of(context).colors.iconDefault, buttonText: 'Clock Out', buttonIcon: ZdsIcons.clock_stop, - buttonSliderColor: ZdsColors.greyWarmSwatch.shade200, + buttonSliderColor: Zeta.of(context).colors.warm.surface, disabledMessage: 'Disabled message that is quite long and goes over two lines', ), ], diff --git a/example/lib/pages/components/calendar.dart b/example/lib/pages/components/calendar.dart index 8485930..5455aab 100644 --- a/example/lib/pages/components/calendar.dart +++ b/example/lib/pages/components/calendar.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:table_calendar/table_calendar.dart'; import 'package:zds_flutter/zds_flutter.dart'; +import 'package:table_calendar/table_calendar.dart'; class CalendarDemo extends StatefulWidget { const CalendarDemo({Key? key}) : super(key: key); @@ -20,13 +20,12 @@ class _CalendarDemoState extends State { child: Column( children: [ TextButton( - onPressed: () { - setState(() { - focusedDate = focusedDate.add(const Duration(days: 1)); - }); - }, - child: const Text('increase day'), - ), + onPressed: () { + setState(() { + focusedDate = focusedDate.add(const Duration(days: 1)); + }); + }, + child: const Text('increase day')), ZdsCalendar( selectedDay: focusedDate, events: [ @@ -100,10 +99,12 @@ class _CalendarDemoState extends State { return DateTime(DateTime.now().year, index + 1, 10); }), isGridShown: true, - singleMarkerBuilder: (context, date, _) { + singleMarkerBuilder: (BuildContext context, DateTime date, dynamic _) { return Container( decoration: BoxDecoration( - color: date.isAfter(DateTime.now()) ? ZdsColors.red : ZdsColors.green, shape: BoxShape.circle), + color: date.isAfter(DateTime.now()) ? Zeta.of(context).colors.red : Zeta.of(context).colors.green, + shape: BoxShape.circle, + ), width: 5, height: 5, ).paddingOnly(top: 7); @@ -134,6 +135,9 @@ class _CalendarDemoState extends State { child: ZdsDateRangePickerDialog( lastDate: DateTime.now().add(const Duration(days: 50)), firstDate: DateTime.now().subtract(const Duration(days: 50)), + startDayOfWeek: 5, + shortMonthDayFormat: 'MM/dd', + shortDateFormat: 'MM/dd/yyyy', ), ); }, diff --git a/example/lib/pages/components/card.dart b/example/lib/pages/components/card.dart index 456ab74..993dd7f 100644 --- a/example/lib/pages/components/card.dart +++ b/example/lib/pages/components/card.dart @@ -1,6 +1,7 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class CardDemo extends StatelessWidget { @@ -79,7 +80,7 @@ class CardDemo extends StatelessWidget { onPressed: () {}, icon: Transform.rotate( angle: math.pi / 2, - child: Icon(ZdsIcons.more_vert, color: ZdsColors.blueGrey), + child: Icon(ZdsIcons.more_vert, color: Zeta.of(context).colors.iconSubtle), ), ), child: const Text('With Header'), @@ -88,9 +89,10 @@ class CardDemo extends StatelessWidget { ], ), ), - const SizedBox(height: 150), - const ZdsDashedLine(child: SizedBox(height: 150, width: 150)), - const SizedBox(height: 150), + const SafeArea( + top: false, + child: SizedBox(), + ), ], ), ), diff --git a/example/lib/pages/components/card_actions.dart b/example/lib/pages/components/card_actions.dart index 134aa11..2e1207d 100644 --- a/example/lib/pages/components/card_actions.dart +++ b/example/lib/pages/components/card_actions.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class CardActionsDemo extends StatelessWidget { @@ -6,6 +7,7 @@ class CardActionsDemo extends StatelessWidget { @override Widget build(BuildContext context) { + final themeData = Theme.of(context); return SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(12), @@ -89,8 +91,8 @@ class CardActionsDemo extends StatelessWidget { ), ZdsTag( rounded: true, - color: ZdsTagColor.error, prefix: Text('U'), + color: ZdsTagColor.error, child: Text('Urgent'), ), ], @@ -112,17 +114,21 @@ class CardActionsDemo extends StatelessWidget { const SizedBox(height: 2), Text( 'District Manager Monthly Walk', - style: Theme.of(context).textTheme.bodyLarge, + style: themeData.textTheme.bodyLarge, ), const SizedBox(height: 8), Text( '04/19/2021 03:35 PM', - style: Theme.of(context).textTheme.titleSmall!.copyWith(color: ZdsColors.blueGrey), + style: themeData.textTheme.titleSmall?.copyWith( + color: Zeta.of(context).colors.textSubtle, + ), ), const SizedBox(height: 16), Text( 'SR-ROC-Rockford IL.00102', - style: Theme.of(context).textTheme.titleSmall!.copyWith(color: ZdsColors.blueGrey), + style: themeData.textTheme.titleSmall?.copyWith( + color: Zeta.of(context).colors.textSubtle, + ), ), ], ) @@ -137,7 +143,7 @@ class CardActionsDemo extends StatelessWidget { children: [ Text( 'Lorem ipsum dolor sit amet consectetur adipiscing elit proin sagittis ipsum at velit bibendum non.', - style: Theme.of(context).textTheme.bodyLarge, + style: themeData.textTheme.bodyLarge, ), ], ), diff --git a/example/lib/pages/components/date_picker.dart b/example/lib/pages/components/date_picker.dart index 8e24d55..bb9d67e 100644 --- a/example/lib/pages/components/date_picker.dart +++ b/example/lib/pages/components/date_picker.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class DatePickerDemo extends StatefulWidget { @@ -44,6 +45,9 @@ class _DatePickerDemoState extends State { labelText: 'Date', ), onChange: (dateTime) {}, + startDayOfWeek: 5, + okClickText: 'ok', + cancelClickText: 'cancel', ), ZdsDateTimePicker( emptyLabel: 'select date', @@ -53,15 +57,23 @@ class _DatePickerDemoState extends State { controller: _controller, inputDecoration: ZdsInputDecoration( labelText: 'Optional Date', - suffixIcon: IconButton( - icon: const Icon( - ZdsIcons.close_circle, - size: 24, - ), - onPressed: () => _controller.value = null, - ), + suffixIcon: _controller.value != null + ? IconButton( + icon: const Icon( + ZdsIcons.close_circle, + size: 24, + ), + onPressed: () { + setState(() { + _controller.value = null; + }); + }, + ) + : null, ), - onChange: (dateTime) {}, + onChange: (dateTime) { + setState(() {}); + }, ), ZdsDateTimePicker( emptyLabel: 'select time', @@ -78,14 +90,17 @@ class _DatePickerDemoState extends State { mode: DateTimePickerMode.time, interval: 15, ), - ZdsListTile( - title: const Text('Build Time'), - trailing: ZdsDateTimePicker( - emptyLabel: 'select date & time', - format: 'MMM dd, yyyy hh:mm a', - textAlign: TextAlign.end, - minDate: DateTime.now(), - mode: DateTimePickerMode.dateAndTime, + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + title: const Text('Build Time'), + trailing: ZdsDateTimePicker( + emptyLabel: 'select date & time', + format: 'MMM dd, yyyy hh:mm a', + textAlign: TextAlign.end, + minDate: DateTime.now(), + mode: DateTimePickerMode.dateAndTime, + ), ), ), const Text('Example with controllers and custom validation:').paddingOnly(top: 8), diff --git a/example/lib/pages/components/default_flutter.dart b/example/lib/pages/components/default_flutter.dart new file mode 100644 index 0000000..dcb2e03 --- /dev/null +++ b/example/lib/pages/components/default_flutter.dart @@ -0,0 +1,200 @@ +import 'package:flutter/material.dart'; +import 'package:zds_flutter/zds_flutter.dart'; + +class DefaultFlutter extends StatelessWidget { + const DefaultFlutter({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: DefaultTabController( + length: 3, + child: SafeArea( + child: ZdsList( + children: [ + Card( + child: Wrap( + spacing: 8, + children: [ + Radio( + value: 'A', + groupValue: 'A', + onChanged: (_) {}, + ), + Radio( + value: 'B', + groupValue: 'A', + onChanged: (_) {}, + ), + Checkbox( + value: true, + onChanged: (_) {}, + ), + Checkbox( + value: false, + onChanged: (_) {}, + ), + Switch( + value: true, + onChanged: (_) {}, + ), + Switch( + value: false, + onChanged: (_) {}, + ), + ], + ), + ), + Card( + child: Column( + children: [ + Slider( + value: 50, + onChanged: (value) {}, + divisions: 10, + min: 0, + max: 100, + ), + Slider( + value: 50, + secondaryTrackValue: 80, + onChanged: (value) {}, + min: 0, + max: 100, + ), + ], + ), + ), + Card( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 23), + child: Column( + children: [ + TextField( + decoration: InputDecoration( + labelText: 'Enter Name', + ), + ), + ], + ), + ), + ), + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 8, + children: [ + ElevatedButton( + onPressed: () { + showDateRangePicker( + context: context, + firstDate: DateTime.now().add(Duration(days: -365)), + lastDate: DateTime.now().add(Duration(days: 365)), + ); + }, + child: Text("Select Date")), + OutlinedButton(onPressed: () {}, child: Text("OutlinedButton")), + TextButton(onPressed: () {}, child: Text("TextButton")), + ], + ), + ), + ), + Card( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + IconButton(onPressed: () {}, icon: Icon(Icons.access_alarm)), + IconButton(onPressed: () {}, icon: Icon(Icons.access_alarm)), + ], + ), + ), + SearchBar(hintText: 'Search with name'), + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 8, + children: [ + Chip( + avatar: Icon(Icons.person), + label: Text('Default Chip'), + ), + Chip( + label: Text('Default Chip'), + onDeleted: () {}, + ), + InputChip( + selected: true, + label: Text('Default Chip'), + onSelected: (_) {}, + ), + InputChip( + isEnabled: false, + label: Text('Default Chip'), + onSelected: (_) {}, + ), + ], + ), + ), + ), + BottomAppBar( + child: Row( + children: [ + TextButton(onPressed: () {}, child: Text("Cancel")), + const Spacer(), + OutlinedButton(onPressed: () {}, child: Text("Reset")), + SizedBox(width: Dimensions.xs), + ElevatedButton(onPressed: () {}, child: Text("Next")), + ], + ), + ), + BottomNavigationBar( + items: [ + BottomNavigationBarItem(label: 'Feeds', icon: Icon(Icons.feed_outlined)), + BottomNavigationBarItem(label: 'Calendar', icon: Icon(Icons.calendar_month)), + ], + ), + TabBar( + tabs: [ + Tab(icon: Icon(Icons.home), text: "Home"), + Tab(icon: Icon(Icons.search), text: "Search"), + Tab(icon: Icon(Icons.settings), text: "Settings"), + ], + ), + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Card'), + ), + ), + ListTile( + leading: Icon(Icons.access_alarm), + trailing: Icon(Icons.chevron_right), + title: Text('ListTile Title'), + subtitle: Text('ListTile Subtitle'), + onTap: () {}, + ), + ListTile( + selected: true, + leading: Icon(Icons.access_alarm), + trailing: Icon(Icons.chevron_right), + title: Text('ListTile Title'), + subtitle: Text('ListTile Subtitle'), + onTap: () {}, + ), + Card( + child: ListTile( + leading: Icon(Icons.access_alarm), + trailing: Icon(Icons.chevron_right), + title: Text('ListTile Title'), + subtitle: Text('ListTile Subtitle'), + ), + ), + ].divide(const SizedBox(height: 20)).toList(), + ), + ), + ), + ); + } +} diff --git a/example/lib/pages/components/empty_view.dart b/example/lib/pages/components/empty_view.dart index fd8b9e7..6676f1d 100644 --- a/example/lib/pages/components/empty_view.dart +++ b/example/lib/pages/components/empty_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class EmptyViewDemo extends StatelessWidget { diff --git a/example/lib/pages/components/expandable.dart b/example/lib/pages/components/expandable.dart index 0247abd..a6ffbe4 100644 --- a/example/lib/pages/components/expandable.dart +++ b/example/lib/pages/components/expandable.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class ExpandableDemo extends StatelessWidget { @@ -23,13 +24,12 @@ class ExpandableDemo extends StatelessWidget { height: 16, ), const ZdsExpandable( - collapsedButtonText: 'Read More', - expandedButtonText: 'Collapse', - child: Text( - 'START Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet END.', - textAlign: TextAlign.justify, - ), - ), + collapsedButtonText: 'Read More', + expandedButtonText: 'Collapse', + child: Text( + 'START Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet END.', + textAlign: TextAlign.justify, + )), ], ).content(), ); diff --git a/example/lib/pages/components/expansion_tile.dart b/example/lib/pages/components/expansion_tile.dart index 4f26ad5..c8bf695 100644 --- a/example/lib/pages/components/expansion_tile.dart +++ b/example/lib/pages/components/expansion_tile.dart @@ -29,213 +29,212 @@ class _ExpansionTileDemoState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: SingleChildScrollView( - child: Column( - children: [ - ZdsCard( - padding: EdgeInsets.zero, - child: Column( - children: [ - ZdsExpansionTile( - initiallyExpanded: true, - title: const Text('Covid Survey'), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Emergency Form 2', style: Theme.of(context).textTheme.bodyMedium).space(8), - Text('Emergency Form 3', style: Theme.of(context).textTheme.bodyMedium).space(8), - Text('Emergency Form 19', style: Theme.of(context).textTheme.bodyMedium).space(), - ], - ), + body: SingleChildScrollView( + padding: EdgeInsets.all(14), + child: Column( + children: [ + ZdsCard( + padding: EdgeInsets.zero, + child: Column( + children: [ + ZdsExpansionTile( + initiallyExpanded: true, + title: const Text('Covid Survey'), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Emergency Form 2', style: Theme.of(context).textTheme.bodyMedium).space(8), + Text('Emergency Form 3', style: Theme.of(context).textTheme.bodyMedium).space(8), + Text('Emergency Form 19', style: Theme.of(context).textTheme.bodyMedium).space(), + ], ), - ZdsExpansionTile( - title: const Text('Customer Service'), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Customer Service Report', style: Theme.of(context).textTheme.bodyMedium).space(8), - Text('New Hire Training Confirmation', style: Theme.of(context).textTheme.bodyMedium).space(), - ], - ), + ), + ZdsExpansionTile( + title: const Text('Customer Service'), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Customer Service Report', style: Theme.of(context).textTheme.bodyMedium).space(8), + Text('New Hire Training Confirmation', style: Theme.of(context).textTheme.bodyMedium).space(), + ], ), - ZdsExpansionTile( - title: const Text('Management Audit Checklist'), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Copy-1712 products and services...', style: Theme.of(context).textTheme.bodyMedium) - .space(), - ], - ), + ), + ZdsExpansionTile( + title: const Text('Management Audit Checklist'), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Copy-1712 products and services...', style: Theme.of(context).textTheme.bodyMedium) + .space(), + ], ), - ZdsExpansionTile( - title: const Text('Store survey Checklist to evaluate the other'), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Survey displays to evaluate if they are...', - style: Theme.of(context).textTheme.bodyMedium, - ).space(8), - Text( - 'Window displays to evaluate if they are...', - style: Theme.of(context).textTheme.bodyMedium, - ).space(), - ], - ), + ), + ZdsExpansionTile( + title: const Text('Store survey Checklist to evaluate the other'), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Survey displays to evaluate if they are...', + style: Theme.of(context).textTheme.bodyMedium, + ).space(8), + Text( + 'Window displays to evaluate if they are...', + style: Theme.of(context).textTheme.bodyMedium, + ).space(), + ], ), - ZdsExpansionTile( - title: const Text('Collect feedback from customers who was'), - initiallyExpanded: true, - titleColor: const Color(0xff007ABA).withOpacity(0.1), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Products and services offered, pricing', style: Theme.of(context).textTheme.bodyMedium) - .space(), - ], - ), + ), + ZdsExpansionTile( + title: const Text('Collect feedback from customers who was'), + initiallyExpanded: true, + titleColor: const Color(0xff007ABA).withOpacity(0.1), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Products and services offered, pricing', style: Theme.of(context).textTheme.bodyMedium) + .space(), + ], ), - ], - ), - ).space(20), - ZdsCard( - padding: EdgeInsets.zero, - child: Column( - children: [ - ZdsExpansionTile( - initiallyExpanded: true, - title: const Text('Covid Survey'), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Emergency Form 2', style: Theme.of(context).textTheme.bodyMedium).space(8), - Text('Emergency Form 3', style: Theme.of(context).textTheme.bodyMedium).space(8), - Text('Emergency Form 19', style: Theme.of(context).textTheme.bodyMedium).space(), - ], - ), + ), + ], + ), + ).space(20), + ZdsCard( + padding: EdgeInsets.zero, + child: Column( + children: [ + ZdsExpansionTile( + initiallyExpanded: true, + title: const Text('Covid Survey'), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Emergency Form 2', style: Theme.of(context).textTheme.bodyMedium).space(8), + Text('Emergency Form 3', style: Theme.of(context).textTheme.bodyMedium).space(8), + Text('Emergency Form 19', style: Theme.of(context).textTheme.bodyMedium).space(), + ], ), - Padding( - padding: const EdgeInsets.all(20), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - ZdsButton.outlined( - child: const Text('Clear'), - onTap: () {}, - ), - ZdsButton( - child: const Text('Apply'), - onTap: () {}, - ), - ], - ), + ), + Padding( + padding: const EdgeInsets.all(20), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ZdsButton.outlined( + child: const Text('Clear'), + onTap: () {}, + ), + const SizedBox(width: 8), + ZdsButton( + child: const Text('Apply'), + onTap: () {}, + ), + ], ), - ], - ), - ).space(20), - ZdsExpansionTile( - title: const Text('Tile outside of a card'), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Sub-tile №1', style: Theme.of(context).textTheme.bodyMedium).space(6), - Text( - 'Another tile that will be hidden after pressing on the expansion tile', - style: Theme.of(context).textTheme.bodyMedium, - ).space(), - ], - ), - ).space(20), - ZdsExpansionTile( - title: const Text('Placeholder Name One'), - contentPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14).copyWith(bottom: 6), - bottom: const Padding( - padding: EdgeInsets.only(left: 22, right: 22, bottom: 8), - child: Row( - children: [ - ZdsTag( - rectangular: true, - child: Text('Read'), - ), - ZdsTag( - rectangular: true, - child: Text('Write'), - ), - ZdsTag( - rectangular: true, - child: Text('Delete'), - ), - ], ), - ), - child: ZdsList( - shrinkWrap: true, + ], + ), + ).space(20), + ZdsExpansionTile( + title: const Text('Tile outside of a card'), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Sub-tile №1', style: Theme.of(context).textTheme.bodyMedium).space(6), + Text( + 'Another tile that will be hidden after pressing on the expansion tile', + style: Theme.of(context).textTheme.bodyMedium, + ).space(), + ], + ), + ).space(20), + ZdsExpansionTile( + title: const Text('Placeholder Name One'), + contentPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14).copyWith(bottom: 6), + bottom: const Padding( + padding: EdgeInsets.only(left: 22, right: 22, bottom: 8), + child: Row( children: [ - SwitchListTile( - contentPadding: const EdgeInsets.symmetric(horizontal: 15), - dense: true, - title: const Text('Read'), - value: true, - onChanged: (val) {}, + ZdsTag( + rectangular: true, + child: Text('Read'), ), - SwitchListTile( - contentPadding: const EdgeInsets.symmetric(horizontal: 15), - dense: true, - title: const Text('Write'), - value: true, - onChanged: (val) {}, + ZdsTag( + rectangular: true, + child: Text('Write'), ), - SwitchListTile( - contentPadding: const EdgeInsets.symmetric(horizontal: 15), - dense: true, - title: const Text('Delete'), - value: true, - onChanged: (val) {}, + ZdsTag( + rectangular: true, + child: Text('Delete'), ), ], ), - ).space(60), - ZdsCard( - padding: EdgeInsets.zero, - child: ZdsExpansionTile.selectable( - titlePadding: const EdgeInsets.all(14), - contentPadding: const EdgeInsets.all(2), - title: const Text('Region 3'), - selected: _selectedItems.length > 1, - onSelected: (isSelected) { - setState(() { - if (isSelected) { - _selectedItems.addAll(_items); - } else { - _selectedItems = []; - } - }); - }, - child: ZdsList.builder( - padding: EdgeInsets.zero, - shrinkWrap: true, - itemCount: _items.length, - itemBuilder: (context, index) { - return ZdsListTile( - shrinkWrap: true, - backgroundColor: Colors.transparent, - title: Text(_items[index].title!).paddingOnly(left: 52), - trailing: _selectedItems.contains(_items[index]) - ? Icon(ZdsIcons.check, color: Theme.of(context).colorScheme.secondary) - : null, - onTap: () { - _itemChange(_items[index], _selectedItems.contains(_items[index])); - }, - ); - }, + ), + child: ZdsList( + shrinkWrap: true, + children: [ + SwitchListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 15), + dense: true, + title: const Text('Read'), + value: true, + onChanged: (val) {}, + ), + SwitchListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 15), + dense: true, + title: const Text('Write'), + value: true, + onChanged: (val) {}, + ), + SwitchListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 15), + dense: true, + title: const Text('Delete'), + value: true, + onChanged: (val) {}, ), + ], + ), + ).space(60), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsExpansionTile.selectable( + titlePadding: const EdgeInsets.all(14), + contentPadding: const EdgeInsets.all(2), + title: const Text('Region 3'), + selected: _selectedItems.length > 1, + onSelected: (isSelected) { + setState(() { + if (isSelected) { + _selectedItems.addAll(_items); + } else { + _selectedItems = []; + } + }); + }, + child: ZdsList.builder( + padding: EdgeInsets.zero, + shrinkWrap: true, + itemCount: _items.length, + itemBuilder: (context, index) { + return ZdsListTile( + shrinkWrap: true, + backgroundColor: Colors.transparent, + title: Text(_items[index].title!).paddingOnly(left: 52), + trailing: _selectedItems.contains(_items[index]) + ? Icon(ZdsIcons.check, color: Theme.of(context).colorScheme.secondary) + : null, + onTap: () { + _itemChange(_items[index], _selectedItems.contains(_items[index])); + }, + ); + }, ), - ).space(20), - ], - ), + ), + ).space(20), + ], ), ), ); diff --git a/example/lib/pages/components/file_picker.dart b/example/lib/pages/components/file_picker.dart index 1194575..abfd0eb 100644 --- a/example/lib/pages/components/file_picker.dart +++ b/example/lib/pages/components/file_picker.dart @@ -43,24 +43,34 @@ class _FilePickerDemoState extends State { visualDensity: VisualDensity.compact, optionDisplay: ZdsOptionDisplay.plain, displayStyle: ZdsFilePickerDisplayStyle.horizontal, + postProcessors: [ + ZdsImageCropPostProcessor(() => context), + const ZdsFileCompressPostProcessor(), + const ZdsFileRenamePostProcessor(), + ], onChange: (files) { debugPrint('files: $files'); }, ), ZdsFilePicker( + useCard: false, config: pickerConfig, controller: controller, - optionDisplay: ZdsOptionDisplay.plain, - displayStyle: ZdsFilePickerDisplayStyle.horizontal, + postProcessors: [ + ZdsFileEditPostProcessor(() => context), + const ZdsFileCompressPostProcessor(), + const ZdsFileRenamePostProcessor(), + ], + visualDensity: VisualDensity.compact, onChange: (files) { debugPrint('files: $files'); }, ), ZdsFilePicker( - useCard: false, config: pickerConfig, controller: controller, - visualDensity: VisualDensity.compact, + optionDisplay: ZdsOptionDisplay.plain, + displayStyle: ZdsFilePickerDisplayStyle.horizontal, onChange: (files) { debugPrint('files: $files'); }, diff --git a/example/lib/pages/components/html_view.dart b/example/lib/pages/components/html_view.dart new file mode 100644 index 0000000..8faddbf --- /dev/null +++ b/example/lib/pages/components/html_view.dart @@ -0,0 +1,731 @@ +import 'package:flutter/material.dart'; +import 'package:zds_flutter/zds_flutter.dart'; + +const mediaHtml = ''' + + + + + Notes + + + + + + + + + +

Media audio url:

+
+
+
+
+
+ +

Media video Url:

+
+
+
+
+
+ +

Links:

+

https://google.com

+

https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4

+

+ + + + +'''; + +const html = ''' + + + + + Notes + + + + + +
+

Bold : Retail describes the sale of a product or service to an individual consumer for personal use. I

talic: The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. Underline: The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

Bold Italic Underline : Retail describes the sale of a product or service to an individual consumer for personal use.The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

Retail describes the sale of a product or service to an individual consumer for personal use.The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

Retail describes the sale of a product or service to an individual consumer for personal use.The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

Retail describes the sale of a product or service to an individual consumer for personal use.The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

  • Hardlines: things that tend to last a long time, such as appliances, cars, and furniture
  • Soft goods or consumables: things like clothing, shoes, and toiletries
  • Food: things like meat, cheese, produce, and baked goods
  • Art: things like fine art, as well as books and musical instruments

Within those categories you’ll also find different types of retail stores. Some of the most common types include:

HTML:

+
Column1Column2Column3Column4Column5Column6Column7
Col1Row1Col2Row1Col3Row1Col4Row1Col5Row1Col6Row1
Col1Row2Col2Row2Col3Row2Col4Row2Col5Row2Col6Row2
Col1Row3Col2Row3Col3Row3Col4Row3Col5Row3Col6Row3
Col1Row4Col2Row4Col3Row4Col4Row4Col5Row4Col6Row4
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Column1Column2Column3Column4Column5Column6Column7
+

Col1Row1

+

Col2Row1

+
Col3Row1Col4Row1Col5Row1 +

Col6Row1

+

Col6Row2

+
Col1Row2 +

Col2Row2

+

Col2Row3

+
+

Col3Row2

+

Col4Row2

+
Col5Row2
Col1Row3Col3Row3Col4Row3Col5Row3Col6Row3
Col1Row4Col2Row4Col3Row4Col4Row4Col5Row4Col6Row4
+
+

+ 1. This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. + 2.This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. + 3. This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. + 4. This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. + 5. This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. +

+

+ This paragraph has multiple spaces. + But HTML reduces them all to a single + space, omitting the extra spaces and line we have used. +

+ + +

Links:

https://google.com

https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4

Media audio url:

Media video Url:

iframe/embedded video

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Column1Column2Column3Column4Column5Column6Column7
Col1Row1Col2Row1Col3Row1Col4Row1Col5Row1Col6Row1
Col1Row2Col2Row2Col3Row2Col4Row2Col5Row2Col6Row2
Col1Row3Col2Row3Col3Row3Col4Row3Col5Row3Col6Row3
Col1Row4Col2Row4Col3Row4Col4Row4Col5Row4Col6Row4
+
+ + + + '''; + +const imgHtml = ''' + + + + + Notes + + + + + +
+ +

What Is Retail?

+

Definitions & Examples of Retail

+

By

+

Barbara Farfan

+

Barbara Farfan

+

Barbara Farfan has 20 years of experience as a business consultant in the retail industry.

+

LEARN ABOUT OUR EDITORIAL POLICIES

+

Updated on November 29, 2022

+

Reviewed by David Kindness

+

Customer looking at mens accessories with shop owner in mens boutique

+

PHOTO: THOMAS BARWICK / GETTY IMAGES

+

Retail is a very broad term that encompasses a huge industry, employing millions of people and generating trillions of dollars per year in sales revenue. Retail is the sale of goods to consumers—not for them to sell, but for use and consumption by the purchaser.

+

This knowledge can help you gain an understanding of the processes involved in getting merchandise to the shelves and the effect a supply chain can have on pricing and sales.

+

What Is Retail?

+

Retail involves the sale of merchandise from a single point of purchase directly to a customer who intends to use that product. The single point of purchase could be a brick-and-mortar retail store, an internet shopping website, or a catalog.

+

Retailing is all about attracting consumers through product displays and marketing. Inventory must be kept, shelves must be kept full, and payments have to be collected. Retailers are more than places to purchase merchandise, however—they provide manufacturers an outlet so that they can focus on creating their products.

+

Note

+

In essence, retailing is the culmination of many different processes brought together to create sales.

+

How Does Retailing Work?

+

Retailers rely on a system that supplies them with merchandise to market to consumers. To acquire inventory and ensure they have the products they want to sell, relationships must be established with businesses that operate within the retail supply chain.

+

+

The retail supply chain consists of manufacturers, wholesalers, retailers, and the consumer (end-user). The wholesaler is directly connected to the manufacturer, while the retailer is connected to the wholesaler.

+

The roles of the key players in a typical retail supply chain are:

+
    +
  • Manufacturers: Produce goods using machines, raw materials, and labor
  • +
  • Wholesalers: Purchase finished goods from the manufacturers and sell those goods to retailers in large bulk quantities
  • +
  • Retailers: Sell the goods in small quantities to the end-user at a higher price, theoretically at the manufacturers suggested retail price
  • +
  • Consumers: Buy the goods from the retailer for personal use
  • +
+ +

List support:

+
    +
  1. This
  2. +
  3. is

  4. +
  5. an
  6. +
  7. + ordered +
      +
    • With

      ...
    • +
    • a
    • +
    • nested
    • +
    • unordered +
        +
      1. With a nested
      2. +
      3. ordered list
      4. +
      5. with a lower alpha list style
      6. +
      7. starting at letter e
      8. +
      +
    • +
    • list
    • +
    +
  8. +
  9. list! Lorem ipsum dolor sit amet.
  10. +
  11. Header 2

  12. +

  13. Header 2
  14. +
+

retail supply chain

+
+ + + + '''; +const tableHtml = ''' + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
qwerq
+ 2132312 + + + 1231wef + + 123456 + + 12345 + + 12345 + +
    +
  • 123
  • +
  • 1243
  • +
+
123
123 +
    +
  1. 12345
  2. +
  3. 32435
  4. +
+
+ 213 + +

12345

+
+ 213 + +
+

12345

+
+
+ 213 + +
12345678
+
ksdlkjhs dajflh +

123

+
+ 213 +
231
+

1231232basdvc ns/,vn d

+

vd vdfsbv'dsfv

+

a vb;sdf vbsd; vbfd; vbj

+
+
+ + + '''; + +const htmlData = r""" +

Scroll to bottom

+

Header 1

+

Header 2

+

Header 3

+

Header 4

+
Header 5
+
Header 6
+ +

Inline Styles:

+

The should be BLUE style='color: blue;'

+

The should be RED style='color: red;'

+

The should be BLACK with 10% alpha style='color: rgba(0, 0, 0, 0.10);

+

The should be GREEN style='color: rgb(0, 97, 0);

+

The should be GREEN style='color: rgb(0, 97, 0);

+ +

Text Alignment

+

Center Aligned Text

+

Right Aligned Text

+

Justified Text

+

Center Aligned Text

+ +

Margins

+
Default Div (width 350px height 20px)
+
margin-left: 3em
+
margin: auto
+
margin: 15px auto
+
margin-left: auto
+
margin-right: auto
+
margin-left: auto; margin-right: 3em
+ +

Margin Auto on Image

+

display:inline-block; margin: auto; (should not center):

+ +

display:block margin: auto; (should center):

+ + +

Support for sub/sup

+ Solve for xn: log2(x2+n) = 93 +

One of the most common equations in all of physics is
E=mc2.

+ +

Ruby Support:

+

+ + 漢かん + 字 + +  is Japanese Kanji. +

+ +

Support for maxLines:

+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vestibulum sapien feugiat lorem tempor, id porta orci elementum. Fusce sed justo id arcu egestas congue. Fusce tincidunt lacus ipsum, in imperdiet felis ultricies eu. In ullamcorper risus felis, ac maximus dui bibendum vel. Integer ligula tortor, facilisis eu mauris ut, ultrices hendrerit ex. Donec scelerisque massa consequat, eleifend mauris eu, mollis dui. Donec placerat augue tortor, et tincidunt quam tempus non. Quisque sagittis enim nisi, eu condimentum lacus egestas ac. Nam facilisis luctus ipsum, at aliquam urna fermentum a. Quisque tortor dui, faucibus in ante eget, pellentesque mattis nibh. In augue dolor, euismod vitae eleifend nec, tempus vel urna. Donec vitae augue accumsan ligula fringilla ultrices et vel ex.
+ + +

Table support (With custom styling!):

+ + + + + + + + + + + + + + + + + + + +
OneTwoThree
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
DataData
+For 50 years, WWF has been protecting the future of nature. +
fDatafDatafData
+ +

List support:

+
    +
  1. This
  2. +
  3. is

  4. +
  5. an
  6. +
  7. + ordered +
      +
    • With

      ...
    • +
    • a
    • +
    • nested
    • +
    • unordered +
        +
      1. With a nested
      2. +
      3. ordered list
      4. +
      5. with a lower alpha list style
      6. +
      7. starting at letter e
      8. +
      +
    • +
    • list
    • +
    +
  8. +
  9. list! Lorem ipsum dolor sit amet.
  10. +
  11. Header 2

  12. +

  13. Header 2
  14. +
+ +

Link support:

+

+ Linking to websites has never been easier. +

+ +

Image support:

+ + + + + + + + + +
Network pngxkcd
Local asset png
Local asset svg
Data uri (with base64 support)Red dot (png) + Green dot (base64 svg) + Green dot (plain svg) +
Custom image render
Broken network imageBroken network image alt text
+ +

SVG support:

+ + + + + + +

Custom Element Support:

+ Inline: <bird></bird> becomes: . +
+ + Block: <flutter></flutter> becomes: + + and <flutter horizontal></flutter> becomes: + + +

MathML Support:

+ + + x + = + + + + - + b + + ± + + + + b + 2 + + - + + 4 + + a + + c + + + + + + 2 + + a + + + + + + + + 0 + 5 + + + x + 2 + + + dx + = + [ + + 1 + 3 + + + x + 3 + + + ] + 0 + 5 + + = + + 125 + 3 + + - + 0 + = + + 125 + 3 + + +
+ + + sin + 2 + + θ + + + + cos + 2 + + θ + = + 1 + + +

Tex Support with the custom tex tag:

+ i\hbar\frac{\partial}{\partial t}\Psi(\vec x,t) = -\frac{\hbar}{2m}\nabla^2\Psi(\vec x,t)+ V(\vec x)\Psi(\vec x,t) +

blockquote:

+
+For 50 years, WWF has been protecting the future of nature. The world's leading conservation organization, WWF works in 100 countries and is supported by 1.2 million members in the United States and close to 5 million globally. +
+

Scroll to top

+"""; + +const testHtml = ''' +

Heading1

Heading 2

Heading 3

Heading 4

Heading 2
Heading 2

Bold :

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Italic :

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Italic :

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Scratch :

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

X2

56565676756566656

Left Align:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Right Align:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Center Align:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Justify Align:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Font:

Comic: Lorem ipsum dolor sit amet, consectetur adipiscing elit,

Courier new: sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Georgia: Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Verdana: Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Font Size

Comic: Lorem ipsum dolor sit amet, consectetur adipiscing elit,

Courier new: sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Georgia: Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Verdana: Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Color:

Red: Lorem ipsum dolor sit amet, consectetur adipiscing elit,

Purple: sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Yellow: Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur Blue: sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Color Background

Orange: nm,fnv,mnbgmbnmm

Red: Duis aute irure dolor in reprehenderit

Purple: Duis aute irure dolor in reprehenderit

Yellow: Duis aute irure dolor in reprehenderit

List-Disc

  • Purple: Duis aute irure dolor in reprehenderit'
  • Purple: Duis aute irure dolor in reprehenderit
  • Purple: Duis aute irure dolor in reprehenderit
  • Purple: Duis aute irure dolor in reprehenderit
  • Purple: Duis aute irure dolor in reprehenderit

List-Circle

  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit

List - Square

  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit

List-Number

  1. Duis aute irure dolor in reprehenderit
  2. Duis aute irure dolor in reprehenderit
  3. Duis aute irure dolor in reprehenderit
  4. Duis aute irure dolor in reprehenderit
  5. Duis aute irure dolor in reprehenderit
  6. Duis aute irure dolor in reprehenderit

List - Alpha

  1. Duis aute irure dolor in reprehenderit
  2. Duis aute irure dolor in reprehenderit
  3. Duis aute irure dolor in reprehenderit
  4. Duis aute irure dolor in reprehenderit
  5. Duis aute irure dolor in reprehenderit
  6. Duis aute irure dolor in reprehenderit

Blockquote:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ + +Page Title + + + +

This is a Heading

+

This is a paragraph.

+ + +

Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1

Test Row Merge

Test Row Merge

Test Column Merge

Test Column Merge

Txt with Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

List-Numbered

  1. Test1
  2. tes2

List - Disc

  • test 1
  • test 2
Bold Italic Underline Scratch123451234

Link:

https://zebra.com

Media: Audio

Media: Video

+ +'''; + +class HtmlPreview extends StatelessWidget { + const HtmlPreview({super.key}); + + @override + Widget build(BuildContext context) { + final htmlList = [mediaHtml, html, htmlData, tableHtml, testHtml, imgHtml]; + return Scaffold( + backgroundColor: Theme.of(context).colorScheme.surface, + appBar: AppBar( + title: const Text('Html Preview'), + ), + body: ListView.separated( + itemBuilder: (BuildContext context, int index) { + final data = htmlList[index]; + return ZdsHtmlContainer( + data, + showReadMore: false, + ); + }, + itemCount: htmlList.length, + padding: EdgeInsets.zero, + separatorBuilder: (BuildContext context, int index) => + const Divider(thickness: 2).paddingOnly(bottom: 10, top: 10), + ), + // SingleChildScrollView(child: ZdsHtmlContainer(mediaHtml, containerWidth: MediaQuery.of(context).size.width,)), + ); + } +} diff --git a/example/lib/pages/components/icon_text_button.dart b/example/lib/pages/components/icon_text_button.dart index 6097e3c..127b01f 100644 --- a/example/lib/pages/components/icon_text_button.dart +++ b/example/lib/pages/components/icon_text_button.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:zds_flutter/zds_flutter.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; class IconTextButtonDemo extends StatelessWidget { const IconTextButtonDemo({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + final zeta = Zeta.of(context); return Center( child: SingleChildScrollView( child: SizedBox( @@ -23,13 +23,13 @@ class IconTextButtonDemo extends StatelessWidget { onTap: () => {onButtonTapped(context)}, icon: ZdsIcons.clock_switch, label: 'Shift Trade', - backgroundColor: ZetaColors.of(context).orange, + backgroundColor: zeta.colors.orange, ), ZdsIconTextButton( onTap: () => {onButtonTapped(context)}, icon: ZdsIcons.clock_available, label: 'Availability', - backgroundColor: ZetaColors.of(context).pink, + backgroundColor: zeta.colors.pink, ) ], ), diff --git a/example/lib/pages/components/image_picker.dart b/example/lib/pages/components/image_picker.dart index 7107fbd..40819dd 100644 --- a/example/lib/pages/components/image_picker.dart +++ b/example/lib/pages/components/image_picker.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class ImagePickerDemo extends StatelessWidget { diff --git a/example/lib/pages/components/index.dart b/example/lib/pages/components/index.dart index 91997e9..cae918f 100644 --- a/example/lib/pages/components/index.dart +++ b/example/lib/pages/components/index.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class IndexDemo extends StatelessWidget { @@ -14,14 +15,14 @@ class IndexDemo extends StatelessWidget { ZdsListTile( leading: ZdsIndex( child: Text('2'), - color: ZdsColors.blue, + color: Zeta.of(context).colors.blue, ), title: Text('Showcase Extravaganza'), ), ZdsListTile( leading: ZdsIndex( child: Text('2'), - color: ZdsColors.purple, + color: Zeta.of(context).colors.purple, ), title: Text('Showcase Extravaganza'), ), diff --git a/example/lib/pages/components/infinite_list.dart b/example/lib/pages/components/infinite_list.dart index 8c0b682..37f0368 100644 --- a/example/lib/pages/components/infinite_list.dart +++ b/example/lib/pages/components/infinite_list.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class InfiniteListDemo extends StatefulWidget { diff --git a/example/lib/pages/components/information_bar.dart b/example/lib/pages/components/information_bar.dart index 0490263..b2640f6 100644 --- a/example/lib/pages/components/information_bar.dart +++ b/example/lib/pages/components/information_bar.dart @@ -1,28 +1,28 @@ import 'package:flutter/material.dart'; import 'package:zds_flutter/zds_flutter.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; class InformationBarDemo extends StatelessWidget { const InformationBarDemo({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + final zeta = Zeta.of(context); return Scaffold( body: Column(children: [ ZdsInformationBar( - zetaColorSwatch: ZetaColors.of(context).green, + zetaColorSwatch: zeta.colors.green, icon: ZdsIcons.check, label: 'Approved', ), SizedBox(height: 10), ZdsInformationBar( - zetaColorSwatch: ZetaColors.of(context).blue, + zetaColorSwatch: zeta.colors.blue, icon: ZdsIcons.hourglass, label: 'Pending', ), SizedBox(height: 10), ZdsInformationBar( - zetaColorSwatch: ZetaColors.of(context).red, + zetaColorSwatch: zeta.colors.red, icon: ZdsIcons.close, label: 'Declined', ), @@ -30,7 +30,7 @@ class InformationBarDemo extends StatelessWidget { ZdsInformationBar( icon: Icons.category, label: 'Neutral text', - zetaColorSwatch: ZetaColors.of(context).warm, + zetaColorSwatch: zeta.colors.warm, ) ]), ); diff --git a/example/lib/pages/components/list_tile.dart b/example/lib/pages/components/list_tile.dart index 2f4b03c..4ae0252 100644 --- a/example/lib/pages/components/list_tile.dart +++ b/example/lib/pages/components/list_tile.dart @@ -1,343 +1,339 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:zds_flutter/zds_flutter.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; class ListTileDemo extends StatelessWidget { const ListTileDemo({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final ZetaColors colors = ZetaColors.of(context); + final zeta = Zeta.of(context); return Scaffold( - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: ListView( - children: [ - const SizedBox(height: 20), - ZdsSelectableListTile( - title: const Text('Urgent'), - subTitle: const Text('32 hours available'), - selected: true, - trailing: ZdsIndex(color: colors.red, child: const Text('U')), - onTap: () {}, + body: ZdsList( + children: [ + const SizedBox(height: 20), + ZdsSelectableListTile( + title: const Text('Urgent'), + subTitle: const Text('32 hours available'), + selected: true, + trailing: ZdsIndex(color: zeta.colors.red, child: const Text('U')), + onTap: () {}, + ), + ZdsSelectableListTile( + title: const Text('High'), + trailing: ZdsIndex(color: zeta.colors.orange, child: const Text('1')), + onTap: () {}, + ), + ZdsSelectableListTile( + title: const Text('Medium'), + trailing: ZdsIndex(color: zeta.colors.teal, child: const Text('2')), + onTap: () {}, + ), + ZdsSelectableListTile( + title: const Text('Low'), + trailing: ZdsIndex(color: zeta.colors.green, child: const Text('3')), + onTap: () {}, + ), + ZdsSelectableListTile.checkable( + title: const Text('Checkable unselected'), + onTap: () {}, + ), + ZdsSelectableListTile.checkable( + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('Checkable selected'), + Text( + 'Checkable unselected', + style: Theme.of(context).textTheme.bodySmall, + ) + ], ), - ZdsSelectableListTile( - title: const Text('High'), - trailing: ZdsIndex(color: colors.orange, child: const Text('1')), - onTap: () {}, + selected: true, + onTap: () {}, + ), + const SizedBox(height: 20), + ZdsListTile( + title: const Text('View summary'), + trailing: TextFormField( + textAlign: TextAlign.end, + decoration: const InputDecoration( + hintText: 'First Name', + ), ), - ZdsSelectableListTile( - title: const Text('Medium'), - trailing: ZdsIndex(color: colors.teal, child: const Text('2')), - onTap: () {}, + ), + ZdsListTile( + leading: const Icon(ZdsIcons.camera), + title: const Text('View summary'), + subtitle: const Text('subtitle'), + trailing: Switch( + onChanged: (_) {}, + value: true, ), - ZdsSelectableListTile( - title: const Text('Low'), - trailing: ZdsIndex(color: colors.green, child: const Text('3')), - onTap: () {}, + ), + ZdsListGroup( + headerLabel: const Text('Search for title, description and unique ID'), + items: [ + const ZdsListTile( + title: Text('View summary'), + subtitle: Text('subtitle'), + trailing: Icon(ZdsIcons.chevron_right), + ), + ZdsListTile( + leading: const Icon(ZdsIcons.search), + title: const Text('With onTap'), + trailing: const Icon(ZdsIcons.chevron_right), + onTap: () {}, + ), + ], + ), + const ZdsListTile( + leading: Icon(ZdsIcons.pdf), + title: Text('View summary'), + trailing: Icon( + ZdsIcons.chevron_right, ), - ZdsSelectableListTile.checkable( - title: const Text('Checkable unselected'), - onTap: () {}, + ), + ZdsListTile( + leading: IconButton( + icon: const Icon(ZdsIcons.pdf), + onPressed: () {}, ), - ZdsSelectableListTile.checkable( - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Checkable selected'), - Text( - 'Checkable unselected', - style: Theme.of(context).textTheme.bodySmall, - ) - ], - ), - selected: true, - onTap: () {}, + title: const Text('This is a very very very long loooong list tile'), + trailing: const Icon( + ZdsIcons.chevron_right, ), - const SizedBox(height: 20), - ZdsListTile( - title: const Text('View summary'), - trailing: TextFormField( - textAlign: TextAlign.end, - decoration: const InputDecoration( - hintText: 'First Name', - ), - ), + ), + ZdsListTile( + leading: IconButton( + icon: const Icon(ZdsIcons.pdf), + onPressed: () {}, ), - ZdsListTile( - leading: const Icon(ZdsIcons.camera), - title: const Text('View summary'), - subtitle: const Text('subtitle'), - trailing: Switch( - onChanged: (_) {}, - value: true, + title: const Text('With icon button normal'), + trailing: IconButton( + onPressed: () {}, + iconSize: 24, + icon: const Icon( + ZdsIcons.chevron_right, ), ), - ZdsListGroup( - headerLabel: const Text('Search for title, description and unique ID'), - items: [ - const ZdsListTile( - title: Text('View summary'), - subtitle: Text('subtitle'), - trailing: Icon(ZdsIcons.chevron_right), + ), + ZdsListGroup( + items: [ + ZdsListTile( + title: Text( + 'Team Leader - Store', + style: TextStyle(color: Theme.of(context).colorScheme.primary), ), - ZdsListTile( - leading: const Icon(ZdsIcons.search), - title: const Text('With onTap'), - trailing: const Icon(ZdsIcons.chevron_right), - onTap: () {}, + trailing: Icon( + ZdsIcons.check, + color: Theme.of(context).colorScheme.primary, ), - ], - ), - const ZdsListTile( - leading: Icon(ZdsIcons.pdf), - title: Text('View summary'), - trailing: Icon( - ZdsIcons.chevron_right, ), - ), - ZdsListTile( - leading: IconButton( - icon: const Icon(ZdsIcons.pdf), - onPressed: () {}, + const ZdsListTile( + title: Text('View summary'), + trailing: Icon(ZdsIcons.check), ), - title: const Text('This is a very very very long loooong list tile'), - trailing: const Icon( - ZdsIcons.chevron_right, + const ZdsListTile( + title: Text('View summary'), + trailing: Icon(ZdsIcons.check), ), + ], + ), + ZdsListTile( + title: Text( + 'Team Leader - Store', + style: TextStyle(color: Theme.of(context).colorScheme.primary), ), - ZdsListTile( - leading: IconButton( - icon: const Icon(ZdsIcons.pdf), - onPressed: () {}, - ), - title: const Text('With icon button normal'), - trailing: IconButton( - onPressed: () {}, - iconSize: 24, - icon: const Icon( - ZdsIcons.chevron_right, - ), - ), + trailing: Icon( + Icons.check, + color: Theme.of(context).colorScheme.primary, ), - ZdsListGroup( - items: [ - ZdsListTile( - title: Text( - 'Team Leader - Store', - style: TextStyle(color: Theme.of(context).colorScheme.primary), - ), - trailing: Icon( - ZdsIcons.check, - color: Theme.of(context).colorScheme.primary, - ), - ), - const ZdsListTile( - title: Text('View summary'), - trailing: Icon(ZdsIcons.check), - ), - const ZdsListTile( - title: Text('View summary'), - trailing: Icon(ZdsIcons.check), - ), - ], + ), + ZdsCard( + child: ZdsPropertiesList( + direction: ZdsPropertiesListDirection.vertical, + properties: { + 'Das URL': '', + }, ), - ZdsListTile( - title: Text( - 'Team Leader - Store', - style: TextStyle(color: Theme.of(context).colorScheme.primary), - ), - trailing: Icon( - Icons.check, - color: Theme.of(context).colorScheme.primary, - ), + ), + ZdsCard( + child: ZdsPropertiesList( + direction: ZdsPropertiesListDirection.vertical, + properties: { + 'Application URL': 'None', + }, ), - ZdsCard( - child: ZdsPropertiesList( - direction: ZdsPropertiesListDirection.vertical, - properties: { - 'Das URL': '', - }, - ), + ), + ZdsListTile( + title: const ZdsPropertiesList( + direction: ZdsPropertiesListDirection.vertical, + properties: { + 'Domain Key': 'Please add', + }, ), - ZdsCard( - child: ZdsPropertiesList( - direction: ZdsPropertiesListDirection.vertical, - properties: { - 'Application URL': 'None', - }, + trailing: IconButton( + icon: Icon( + Icons.add, + color: Theme.of(context).primaryColor, ), + onPressed: () {}, ), - ZdsListTile( - title: const ZdsPropertiesList( - direction: ZdsPropertiesListDirection.vertical, - properties: { - 'Domain Key': 'Please add', - }, - ), - trailing: IconButton( - icon: Icon( - Icons.add, - color: Theme.of(context).primaryColor, + ), + const ZdsListTile( + title: Text('View summary'), + trailing: Icon(ZdsIcons.check), + ), + const ZdsListTile( + title: Text('View summary'), + trailing: Icon(ZdsIcons.chevron_right), + ), + const ZdsListTile( + leading: Icon(ZdsIcons.pdf), + title: Text('Unique ID'), + trailing: Text('Unique ID'), + ), + const ZdsListTile( + leading: Icon(ZdsIcons.pdf), + title: Text('View type'), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text('My walks'), + SizedBox(width: 10), + Icon(ZdsIcons.chevron_right), + ], + ), + ), + ZdsListTile( + onTap: () {}, + title: const Text('Notes'), + bottom: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider(), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24), + child: const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('• This is a bullet point list'), + Text('• Next point'), + Text('• More information'), + ], + ).textStyle(Theme.of(context).textTheme.bodyLarge), ), - onPressed: () {}, - ), + ], ), - const ZdsListTile( - title: Text('View summary'), - trailing: Icon(ZdsIcons.check), + ), + ZdsListTile( + onTap: () {}, + contentPadding: kZdsListTileTheme.contentPadding.copyWith(left: 0), + title: const Text('Not scheduled today'), + leading: Container( + width: 6, + height: 65, + color: zeta.colors.red, ), - const ZdsListTile( - title: Text('View summary'), - trailing: Icon(ZdsIcons.chevron_right), + ), + ZdsNotificationTile( + dateLabel: 'MMM dd, yyyy hh:mm a', + content: 'PTO Request approved for Mon at Jan 11 at 11:00 am', + ), + ZdsNotificationTile( + onTap: () {}, + dateLabel: getNotificationDate(), + content: 'Meeting with Jordan Smith at Jan 11 at 11:00 am', + leadingData: Icon( + ZdsIcons.lightbulb, + color: zeta.colors.orange, + size: 16, ), - const ZdsListTile( - leading: Icon(ZdsIcons.pdf), - title: Text('Unique ID'), - trailing: Text('Unique ID'), + ), + ZdsFieldsListTile( + shrink: false, + title: const Text( + 'Title of the Project - 0001 Client > Zone 6_thiscan go upwards of two or three lines_ Coporateconfiguration', ), - const ZdsListTile( - leading: Icon(ZdsIcons.pdf), - title: Text('View type'), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text('My walks'), - SizedBox(width: 10), - Icon(ZdsIcons.chevron_right), - ], + fields: const [ + TileField( + start: Text('Start/End'), + end: Text('07/05/2021 - 07/05/2021'), ), - ), - ZdsListTile( - onTap: () {}, - title: const Text('Notes'), - bottom: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Divider(), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24), - child: const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('• This is a bullet point list'), - Text('• Next point'), - Text('• More information'), - ], - ).textStyle(Theme.of(context).textTheme.bodyLarge), - ), - ], + TileField( + start: Text('Approval Date'), + end: Text('07/06/2021 16;45 PST'), ), - ), - ZdsListTile( - onTap: () {}, - contentPadding: Theme.of(context).zdsListTileThemeData.contentPadding.copyWith(left: 0), - title: const Text('Not scheduled today'), - leading: Container( - width: 6, - height: 65, - color: ZetaColors.of(context).red, + TileField( + start: Text('Status?'), + end: Text('N/A'), ), + ], + footnote: const Text( + 'You have exceeded your balance. You will be eligible to take more time off after March 1.', ), - ZdsNotificationTile( - dateLabel: 'MMM dd, yyyy hh:mm a', - content: 'PTO Request approved for Mon at Jan 11 at 11:00 am', + data: 'Any object', + onTap: (String? data) { + debugPrint(data ?? ''); + }, + ), + ZdsFieldsListTile( + title: Row( + children: [ + Icon( + ZdsIcons.task, + color: Theme.of(context).primaryColor, + size: 25, + ).paddingOnly(right: 10), + Text( + 'Manual Task Survey 2', + style: Theme.of(context) + .textTheme + .bodyLarge! + .copyWith(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold), + ), + ], ), - ZdsNotificationTile( - onTap: () {}, - dateLabel: getNotificationDate(), - content: 'Meeting with Jordan Smith at Jan 11 at 11:00 am', - leadingData: Icon( - ZdsIcons.lightbulb, - color: ZetaColors.of(context).orange, - size: 16, + fieldsEndTextStyle: Theme.of(context).textTheme.bodyLarge, + fields: const [ + TileField( + start: Text('Execution level'), + end: Text('Store'), ), - ), - ZdsFieldsListTile( - shrink: false, - title: const Text( - 'Title of the Project - 0001 Client > Zone 6_thiscan go upwards of two or three lines_ Coporateconfiguration', + TileField( + start: Text('Assigned'), + end: Text('Store Manager'), ), - fields: const [ - TileField( - start: Text('Start/End'), - end: Text('07/05/2021 - 07/05/2021'), - ), - TileField( - start: Text('Approval Date'), - end: Text('07/06/2021 16;45 PST'), - ), - TileField( - start: Text('Status?'), - end: Text('N/A'), - ), - ], - footnote: const Text( - 'You have exceeded your balance. You will be eligible to take more time off after March 1.', + TileField( + start: Text('Department'), + end: Text('Store'), ), - data: 'Any object', - onTap: (String? data) { - debugPrint(data ?? ''); - }, - ), - ZdsFieldsListTile( - title: Row( - children: [ - Icon( - ZdsIcons.task, - color: Theme.of(context).primaryColor, - size: 25, - ).paddingOnly(right: 10), - Text( - 'Manual Task Survey 2', - style: Theme.of(context) - .textTheme - .bodyLarge! - .copyWith(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold), - ), - ], + TileField( + start: Text('Type'), + end: Text('System'), ), - fieldsEndTextStyle: Theme.of(context).textTheme.bodyLarge, - fields: const [ - TileField( - start: Text('Execution level'), - end: Text('Store'), - ), - TileField( - start: Text('Assigned'), - end: Text('Store Manager'), - ), - TileField( - start: Text('Department'), - end: Text('Store'), - ), - TileField( - start: Text('Type'), - end: Text('System'), - ), - ], - data: 'Any object', - onTap: (String? data) {}, - ), - ZdsFieldsListTile( - startFieldFlexFactor: 2, - fieldsStartTextStyle: Theme.of(context).textTheme.bodyMedium, - fieldsEndTextStyle: Theme.of(context).textTheme.bodyMedium, - fields: const [ - TileField( - start: Text('Maximum number of days'), - end: Text('4 days'), - ), - TileField( - start: Text('Effective by'), - end: Text('Friday, Jan 20 2023'), - ), - ], - ) - ], - ), + ], + data: 'Any object', + onTap: (String? data) {}, + ), + ZdsFieldsListTile( + startFieldFlexFactor: 2, + fieldsStartTextStyle: Theme.of(context).textTheme.bodyMedium, + fieldsEndTextStyle: Theme.of(context).textTheme.bodyMedium, + fields: const [ + TileField( + start: Text('Maximum number of days'), + end: Text('4 days'), + ), + TileField( + start: Text('Effective by'), + end: Text('Friday, Jan 20 2023'), + ), + ], + ) + ].divide(const SizedBox(height: 16)).toList(), ), ); } diff --git a/example/lib/pages/components/list_tile_wrapper.dart b/example/lib/pages/components/list_tile_wrapper.dart new file mode 100644 index 0000000..7f0e124 --- /dev/null +++ b/example/lib/pages/components/list_tile_wrapper.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:zds_flutter/zds_flutter.dart'; + +class ListTileWrapperDemo extends StatelessWidget { + const ListTileWrapperDemo({super.key}); + + static const tileCount = 6; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: ListView.builder( + itemCount: tileCount, + padding: const EdgeInsets.all(14), + itemBuilder: (context, index) { + return ZdsListTileWrapper( + top: index == 0, + bottom: index == (tileCount - 1), + child: ZdsListTile( + title: Text('Title $index'), + subtitle: Text('Subtitle $index'), + onTap: () {}, + ), + ); + }, + ), + ); + } +} diff --git a/example/lib/pages/components/modal.dart b/example/lib/pages/components/modal.dart index f3e62b7..83f34fb 100644 --- a/example/lib/pages/components/modal.dart +++ b/example/lib/pages/components/modal.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class ModalDemo extends StatelessWidget { diff --git a/example/lib/pages/components/popover.dart b/example/lib/pages/components/popover.dart index 1ebc910..7d78db2 100644 --- a/example/lib/pages/components/popover.dart +++ b/example/lib/pages/components/popover.dart @@ -26,8 +26,7 @@ class _PopOverDemoState extends State { padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 25), child: child ?? const Text( - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - ), + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'), ), ); } @@ -43,17 +42,18 @@ class _PopOverDemoState extends State { icon: const Icon(ZdsIcons.info), popOverBuilder: (context) { return const Text( - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - ).paddingInsets(_contentPadding); + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.') + .paddingInsets(_contentPadding); }, ), ZdsPopOverIconButton( icon: const Icon(ZdsIcons.sort), - backgroundColor: ZdsColors.red, + backgroundColor: Zeta.of(context).colors.red, popOverBuilder: (context) { return Container( - child: const Text('Lorem ipsum dolor sit amet.') - .textStyle(Theme.of(context).textTheme.bodyLarge!.copyWith(color: ZdsColors.white)), + child: const Text('Lorem ipsum dolor sit amet.').textStyle( + Theme.of(context).textTheme.bodyLarge?.copyWith(color: Zeta.of(context).colors.red.onColor), + ), ).paddingInsets(_contentPadding); }, ), diff --git a/example/lib/pages/components/profile.dart b/example/lib/pages/components/profile.dart index a8b1aa1..162a66e 100644 --- a/example/lib/pages/components/profile.dart +++ b/example/lib/pages/components/profile.dart @@ -23,7 +23,7 @@ class ProfileDemo extends StatelessWidget { image: Image.network( 'https://www.zebra.com/content/dam/zebra_dam/global/graphics/logos/zebra-logo-black-stacked.png', ), - backgroundColor: ZdsColors.white, + backgroundColor: Theme.of(context).colorScheme.surface, ), nameText: const Text('Jason Davis'), jobTitleText: const Text('Store Manager'), diff --git a/example/lib/pages/components/properties_list.dart b/example/lib/pages/components/properties_list.dart index 41b6e77..79d539d 100644 --- a/example/lib/pages/components/properties_list.dart +++ b/example/lib/pages/components/properties_list.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class PropertiesListDemo extends StatelessWidget { diff --git a/example/lib/pages/components/quill_editor_demo.dart b/example/lib/pages/components/quill_editor_demo.dart new file mode 100644 index 0000000..654e791 --- /dev/null +++ b/example/lib/pages/components/quill_editor_demo.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:zds_flutter/zds_flutter.dart'; + +///Example for htmlEditor +class QuillEditorDemo extends StatefulWidget { + const QuillEditorDemo({super.key}); + + @override + State createState() => _QuillEditorDemoState(); +} + +class _QuillEditorDemoState extends State { + final controller = QuillController.basic(); + + @override + void initState() { + super.initState(); + ZdsQuillDelta.fromHtml(''' +

H1 heading

H2 Heading

H3 Heading

Normal
Because

+ ''').then((value) { + controller.document = value.document; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Quill Editor')), + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.edit), + onPressed: () { + ZdsQuillEditorPage.edit( + context, + title: 'Edit Notes', + initialDelta: ZdsQuillDelta(document: controller.document), + charLimit: 200, + ).then((value) { + if (value != null) { + controller.document = value.document; + } + }); + }, + ), + body: Column( + children: [ + Expanded( + child: QuillEditor.basic( + padding: const EdgeInsets.all(16), + controller: controller, + readOnly: true, + ), + ), + ], + ), + ); + } +} diff --git a/example/lib/pages/components/radio_list.dart b/example/lib/pages/components/radio_list.dart index 15b531d..696c461 100644 --- a/example/lib/pages/components/radio_list.dart +++ b/example/lib/pages/components/radio_list.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; enum WalkDateRange { @@ -38,6 +39,20 @@ class RadioListDemo extends StatelessWidget { ], onChange: (item) => debugPrint(item is WalkDate ? item.label : ''), ).space(), + ZdsRadioList( + initialValue: const WalkDate('Current Month', WalkDateRange.currentMonth), + condensed: true, + items: const [ + WalkDate('Current Week', WalkDateRange.currentWeek), + WalkDate('Last Week', WalkDateRange.lastWeek), + WalkDate('Current Month', WalkDateRange.currentMonth), + WalkDate('Last Month', WalkDateRange.lastMonth), + WalkDate('YTD', WalkDateRange.yearToDate), + WalkDate('Last X days', WalkDateRange.lastXDays), + WalkDate('Specific Dates', WalkDateRange.specificDates), + ], + onChange: (item) => debugPrint(item is WalkDate ? item.label : ''), + ).space(), ZdsCard( padding: EdgeInsets.zero, child: ZdsExpansionTile( diff --git a/example/lib/pages/components/search.dart b/example/lib/pages/components/search.dart index e51fb36..2b828a7 100644 --- a/example/lib/pages/components/search.dart +++ b/example/lib/pages/components/search.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; class SearchDemo extends StatefulWidget { const SearchDemo({Key? key}) : super(key: key); @@ -50,10 +50,7 @@ class _SearchDemoState extends State { Widget build(BuildContext context) { final clearButton = _showSuffixClearButton ? IconButton( - icon: Icon( - ZdsIcons.close_circle, - color: ZetaColors.of(context).textSubtle, - ), + icon: Icon(ZdsIcons.close_circle, color: Zeta.of(context).colors.iconSubtle), onPressed: _clearButtonFieldController.clear, ) : null; @@ -63,7 +60,7 @@ class _SearchDemoState extends State { leading: IconButton( icon: Icon( ZdsIcons.search_advance, - color: Theme.of(context).primaryColor, + color: Theme.of(context).colorScheme.primary, ), onPressed: _toggleSearchOverlay, ), @@ -86,8 +83,7 @@ class _SearchDemoState extends State { color: Theme.of(context).primaryColor, ).padding(5), const Text('Try smart search').textStyle( - Theme.of(context).textTheme.titleSmall!.copyWith(color: Theme.of(context).primaryColor), - ) + Theme.of(context).textTheme.titleSmall!.copyWith(color: Theme.of(context).primaryColor)) ], ), ) diff --git a/example/lib/pages/components/shake_example.dart b/example/lib/pages/components/shake_example.dart index d831b67..6a3812f 100644 --- a/example/lib/pages/components/shake_example.dart +++ b/example/lib/pages/components/shake_example.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class ShakeExample extends StatefulWidget { diff --git a/example/lib/pages/components/sheet_header.dart b/example/lib/pages/components/sheet_header.dart index 8d79562..b30bfbe 100644 --- a/example/lib/pages/components/sheet_header.dart +++ b/example/lib/pages/components/sheet_header.dart @@ -70,19 +70,21 @@ class SheetHeaderDemo extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ ZdsListTile( - leading: const Text('Urgent'), trailing: ZdsIndex(color: ZdsColors.red, child: const Text('U'))), + leading: const Text('Urgent'), + trailing: ZdsIndex(color: Zeta.of(context).colors.red, child: const Text('U')), + ), ZdsListTile( leading: const Text('High'), - trailing: ZdsIndex(color: ZdsColors.orange, child: const Text('1')), + trailing: ZdsIndex(color: Zeta.of(context).colors.orange, child: const Text('1')), ), ZdsListTile( leading: const Text('Medium'), - trailing: ZdsIndex(color: ZdsColors.teal, child: const Text('2')), + trailing: ZdsIndex(color: Zeta.of(context).colors.teal, child: const Text('2')), ), ZdsListTile( leading: const Text('Low'), trailing: ZdsIndex( - color: ZdsColors.green, + color: Zeta.of(context).colors.green, child: const Text('3'), ), ), diff --git a/example/lib/pages/components/slidable_list_tile.dart b/example/lib/pages/components/slidable_list_tile.dart index 82f7061..5f5b0cb 100644 --- a/example/lib/pages/components/slidable_list_tile.dart +++ b/example/lib/pages/components/slidable_list_tile.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class SlidableListTileDemo extends StatelessWidget { @@ -6,6 +7,8 @@ class SlidableListTileDemo extends StatelessWidget { @override Widget build(BuildContext context) { + var themeData = Theme.of(context); + var zetaColors = Zeta.of(context).colors; return Scaffold( body: Padding( padding: const EdgeInsets.all(8), @@ -15,13 +18,15 @@ class SlidableListTileDemo extends StatelessWidget { onTap: () => debugPrint('Main tile tap'), width: MediaQuery.of(context).size.width, actions: [ - ZdsSlidableAction(label: 'More'), ZdsSlidableAction( - icon: ZdsIcons.sign_out, - label: 'Exit', - onPressed: (_) => debugPrint('Exit'), - backgroundColor: Theme.of(context).colorScheme.error, - ) + label: 'More', + ), + ZdsSlidableAction( + icon: ZdsIcons.sign_out, + label: 'Exit', + onPressed: (_) => debugPrint('Exit'), + backgroundColor: themeData.colorScheme.error, + foregroundColor: themeData.colorScheme.onError) ], child: const _ExampleContent( leading: CircleAvatar(child: Text('JC')), @@ -37,11 +42,10 @@ class SlidableListTileDemo extends StatelessWidget { width: MediaQuery.of(context).size.width, leadingActions: [ ZdsSlidableAction( - icon: Icons.restaurant, - label: 'Kadabra', - backgroundColor: const Color(0xFF6D534E), - foregroundColor: Colors.white, - ), + icon: Icons.restaurant, + label: 'Kadabra', + backgroundColor: const Color(0xFF6D534E), + foregroundColor: Colors.white), ZdsSlidableAction( icon: Icons.flatware, label: 'Alakazam', @@ -50,11 +54,10 @@ class SlidableListTileDemo extends StatelessWidget { ], actions: [ ZdsSlidableAction( - icon: Icons.restaurant, - label: 'Kadabra', - backgroundColor: const Color(0xFF6D534E), - foregroundColor: Colors.white, - ), + icon: Icons.restaurant, + label: 'Kadabra', + backgroundColor: const Color(0xFF6D534E), + foregroundColor: Colors.white), ZdsSlidableAction( icon: Icons.flatware, label: 'Alakazam', @@ -86,11 +89,10 @@ class SlidableListTileDemo extends StatelessWidget { ], actions: [ ZdsSlidableAction( - icon: Icons.restaurant, - label: 'Kadabra', - backgroundColor: const Color(0xFF6D534E), - foregroundColor: Colors.white, - ), + icon: Icons.restaurant, + label: 'Kadabra', + backgroundColor: const Color(0xFF6D534E), + foregroundColor: Colors.white), ZdsSlidableAction( icon: Icons.flatware, label: 'Alakazam', @@ -109,25 +111,24 @@ class SlidableListTileDemo extends StatelessWidget { height: 60, child: ZdsSlidableListTile( slideButtonWidth: 120, - backgroundColor: ZdsColors.red, + backgroundColor: zetaColors.red, width: MediaQuery.of(context).size.width, actions: [ ZdsSlidableAction( label: 'Give away', - backgroundColor: Theme.of(context).colorScheme.secondary, - foregroundColor: ZdsColors.white, + backgroundColor: themeData.colorScheme.secondary, + foregroundColor: themeData.colorScheme.secondary.onColor, ), ZdsSlidableAction( label: 'Direct swap', - backgroundColor: const Color(0xff7D3CBC), - foregroundColor: ZdsColors.white, + backgroundColor: zetaColors.purple, + foregroundColor: zetaColors.purple.onColor, ), ZdsSlidableAction( - label: 'Swap with anyone', - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, - foregroundColor: ZdsColors.white, - textOverflow: TextOverflow.visible, - ) + label: 'Swap with anyone', + backgroundColor: themeData.colorScheme.secondaryContainer, + foregroundColor: themeData.colorScheme.secondaryContainer.onColor, + textOverflow: TextOverflow.visible) ], child: const Center(child: Text('A list tile with 3 slidable action buttons')), ), diff --git a/example/lib/pages/components/split_navigator.dart b/example/lib/pages/components/split_navigator.dart index dd920d5..0cab4c4 100644 --- a/example/lib/pages/components/split_navigator.dart +++ b/example/lib/pages/components/split_navigator.dart @@ -11,6 +11,7 @@ class SplitNavigatorDemo extends StatefulWidget { class _SplitNavigatorDemoState extends State { int _currentIndex = 0; + int get currentIndex => _currentIndex; set currentIndex(int currentIndex) { diff --git a/example/lib/pages/components/stats_card.dart b/example/lib/pages/components/stats_card.dart index 7ecd75d..a2c75ef 100644 --- a/example/lib/pages/components/stats_card.dart +++ b/example/lib/pages/components/stats_card.dart @@ -7,65 +7,63 @@ class StatsCardDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - body: SingleChildScrollView( - child: Column( - children: [ - ZdsStatCard( - stats: const [ - ZdsStat(value: 72.3, description: 'Par'), - ], - title: 'Course Details', - subtitle: 'Really really long subtitle', - ).padding(8), - ZdsStatCard( - stats: [ - const ZdsStat(value: 40, description: 'Total Hours'), - ZdsStat( - value: 32.4, - description: 'Remaining', - color: ZdsColors.green, - ) - ], - title: 'Medical', - subtitle: 'Accrual: 01/22/2022', - ).padding(8), - ZdsStatCard( - stats: [ - const ZdsStat(value: 2.25, description: 'Total Days'), - const ZdsStat(value: 1, description: 'Used'), - ZdsStat( - value: 1.75, - description: 'Remaining', - color: ZdsColors.green, - ) - ], - title: 'Floating Holidays', - ).padding(8), - ZdsStatCard( - stats: [ - const ZdsStat(value: 10, description: 'Total Hours'), - const ZdsStat(value: 2, description: 'Used'), - const ZdsStat(value: 3, description: 'Scheduled'), - ZdsStat( - value: 5, - description: 'Remaining', - color: ZdsColors.green, - ) - ], - title: 'Vacation', - ).padding(8), - // Title-less card - ZdsStatCard( - subtitle: 'Subtitle', - stats: const [ - ZdsStat(value: 7, description: 'Carbon'), - ZdsStat(value: 16, description: 'Hydrogen'), - ZdsStat(value: 1, description: 'Nitrogen'), - ZdsStat(value: 2, description: 'Oxygen') - ], - ).padding(8), - ], - ), + body: ZdsList( + children: [ + ZdsStatCard( + stats: const [ + ZdsStat(value: 72.3, description: 'Par'), + ], + title: 'Course Details', + subtitle: 'Really really long subtitle', + ).padding(8), + ZdsStatCard( + stats: [ + const ZdsStat(value: 40, description: 'Total Hours'), + ZdsStat( + value: 32.4, + description: 'Remaining', + color: Zeta.of(context).colors.green, + ) + ], + title: 'Medical', + subtitle: 'Accrual: 01/22/2022', + ).padding(8), + ZdsStatCard( + stats: [ + const ZdsStat(value: 2.25, description: 'Total Days'), + const ZdsStat(value: 1, description: 'Used'), + ZdsStat( + value: 1.75, + description: 'Remaining', + color: Zeta.of(context).colors.green, + ) + ], + title: 'Floating Holidays', + ).padding(8), + ZdsStatCard( + stats: [ + const ZdsStat(value: 10, description: 'Total Hours'), + const ZdsStat(value: 2, description: 'Used'), + const ZdsStat(value: 3, description: 'Scheduled'), + ZdsStat( + value: 5, + description: 'Remaining', + color: Zeta.of(context).colors.green, + ) + ], + title: 'Vacation', + ).padding(8), + // Title-less card + ZdsStatCard( + subtitle: 'Subtitle', + stats: const [ + ZdsStat(value: 7, description: 'Carbon'), + ZdsStat(value: 16, description: 'Hydrogen'), + ZdsStat(value: 1, description: 'Nitrogen'), + ZdsStat(value: 2, description: 'Oxygen') + ], + ).padding(8), + ], ), ); } diff --git a/example/lib/pages/components/tab_bar.dart b/example/lib/pages/components/tab_bar.dart index 48abca5..6e7b45a 100644 --- a/example/lib/pages/components/tab_bar.dart +++ b/example/lib/pages/components/tab_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class TabBarDemo extends StatefulWidget { @@ -57,30 +58,41 @@ class _TabBarDemoState extends State with SingleTickerProviderStateM label: 'History', ), ]; - return Scaffold( - appBar: AppBar( - elevation: 0, - ), - body: DefaultTabController( - length: 5, - child: SingleChildScrollView( + return DefaultTabController( + length: 5, + child: Scaffold( + appBar: AppBar( + elevation: 0, + ), + body: SingleChildScrollView( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('Colors: primary, basic, surface', style: Theme.of(context).textTheme.displaySmall), Text('ZdsTabBar with icons', style: Theme.of(context).textTheme.displaySmall), ZdsTabBar(color: ZdsTabBarColor.primary, tabs: items2), ZdsTabBar(color: ZdsTabBarColor.basic, tabs: items2), - ZdsTabBar(color: ZdsTabBarColor.surface, tabs: items2), + ZdsCard( + child: ZdsTabBar( + isScrollable: true, + color: ZdsTabBarColor.surface, + tabs: items2, + ), + ), Text('ZdsResponsiveTabBar with icons', style: Theme.of(context).textTheme.displaySmall), - SizedBox( - width: 345, - child: Column( - children: [ - ZdsResponsiveTabBar(color: ZdsTabBarColor.primary, tabs: items2), - ZdsResponsiveTabBar(color: ZdsTabBarColor.basic, tabs: items2), - ZdsResponsiveTabBar(color: ZdsTabBarColor.surface, tabs: items2), - ], + ZdsCard( + child: ZdsResponsiveTabBar(color: ZdsTabBarColor.surface, tabs: items2), + ), + Center( + child: SizedBox( + width: 345, + child: Column( + children: [ + ZdsResponsiveTabBar(color: ZdsTabBarColor.primary, tabs: items2), + ZdsResponsiveTabBar(color: ZdsTabBarColor.basic, tabs: items2), + ZdsResponsiveTabBar(color: ZdsTabBarColor.surface, tabs: items2), + ], + ), ), ), Text('ZdsTabBar without icons', style: Theme.of(context).textTheme.displaySmall), @@ -88,14 +100,18 @@ class _TabBarDemoState extends State with SingleTickerProviderStateM ZdsTabBar(color: ZdsTabBarColor.basic, tabs: items2.map((e) => e.withoutIcon).toList()), ZdsTabBar(color: ZdsTabBarColor.surface, tabs: items2.map((e) => e.withoutIcon).toList()), Text('ZdsResponsiveTabBar without icons', style: Theme.of(context).textTheme.displaySmall), - SizedBox( - width: 345, - child: Column( - children: [ - ZdsResponsiveTabBar(color: ZdsTabBarColor.primary, tabs: items2.map((e) => e.withoutIcon).toList()), - ZdsResponsiveTabBar(color: ZdsTabBarColor.basic, tabs: items2.map((e) => e.withoutIcon).toList()), - ZdsResponsiveTabBar(color: ZdsTabBarColor.surface, tabs: items2.map((e) => e.withoutIcon).toList()), - ], + Center( + child: SizedBox( + width: 345, + child: Column( + children: [ + ZdsResponsiveTabBar( + color: ZdsTabBarColor.primary, tabs: items2.map((e) => e.withoutIcon).toList()), + ZdsResponsiveTabBar(color: ZdsTabBarColor.basic, tabs: items2.map((e) => e.withoutIcon).toList()), + ZdsResponsiveTabBar( + color: ZdsTabBarColor.surface, tabs: items2.map((e) => e.withoutIcon).toList()), + ], + ), ), ), Text('ZdsTabBar without text', style: Theme.of(context).textTheme.displaySmall), @@ -103,19 +119,27 @@ class _TabBarDemoState extends State with SingleTickerProviderStateM ZdsTabBar(color: ZdsTabBarColor.basic, tabs: items2.map((e) => e.withoutText).toList()), ZdsTabBar(color: ZdsTabBarColor.surface, tabs: items2.map((e) => e.withoutText).toList()), Text('ZdsResponsiveTabBar without text', style: Theme.of(context).textTheme.displaySmall), - SizedBox( - width: 245, - child: Column( - children: [ - ZdsResponsiveTabBar(color: ZdsTabBarColor.primary, tabs: items2.map((e) => e.withoutText).toList()), - ZdsResponsiveTabBar(color: ZdsTabBarColor.basic, tabs: items2.map((e) => e.withoutText).toList()), - ZdsResponsiveTabBar(color: ZdsTabBarColor.surface, tabs: items2.map((e) => e.withoutText).toList()), - ], + Center( + child: SizedBox( + width: 245, + child: Column( + children: [ + ZdsResponsiveTabBar( + color: ZdsTabBarColor.primary, tabs: items2.map((e) => e.withoutText).toList()), + ZdsResponsiveTabBar(color: ZdsTabBarColor.basic, tabs: items2.map((e) => e.withoutText).toList()), + ZdsResponsiveTabBar( + color: ZdsTabBarColor.surface, tabs: items2.map((e) => e.withoutText).toList()), + ], + ), ), ), ].divide(const SizedBox(height: 40)).toList(), ), ), + bottomNavigationBar: ZdsResponsiveTabBar( + color: ZdsTabBarColor.surface, + tabs: items2.map((e) => e.withoutText).toList(), + ), ), ); } diff --git a/example/lib/pages/components/tag.dart b/example/lib/pages/components/tag.dart index fa0d83c..304fe5e 100644 --- a/example/lib/pages/components/tag.dart +++ b/example/lib/pages/components/tag.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class TagDemo extends StatelessWidget { @@ -6,161 +7,217 @@ class TagDemo extends StatelessWidget { @override Widget build(BuildContext context) { + final zetaColors = Zeta.of(context).colors; return Scaffold( - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: SingleChildScrollView( - child: Column( - children: [ - const ZdsListTile( - trailing: ZdsTag( - child: Text('Incomplete'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - color: ZdsTagColor.primary, - child: const Text('Pending Review'), - ), - ), - const SizedBox(height: 20), - ZdsListTile( - trailing: ZdsTag( - rounded: true, - prefix: const Text('U'), - color: ZdsTagColor.error, - child: const Text('Urgent'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - rounded: true, - prefix: const Text('1'), - color: ZdsTagColor.alert, - child: const Text('High Priority'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - rounded: true, - prefix: const Text('2'), - color: ZdsTagColor.secondary, - child: const Text('Medium Priority'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - rounded: true, - prefix: const Text('3'), - color: ZdsTagColor.success, - child: const Text('Low Priority'), - ), - ), - const SizedBox(height: 20), - const ZdsListTile( - trailing: ZdsTag( - filled: true, - child: Text('Default'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - filled: true, - color: ZdsTagColor.error, - child: const Text('Urgent'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - filled: true, - color: ZdsTagColor.alert, - child: const Text('High Priority'), - ), - ), - const ZdsListTile( - trailing: ZdsTag( - filled: true, - child: Text('Primary'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - filled: true, - color: ZdsTagColor.primary, - child: const Text('Medium Priority'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - filled: true, - color: ZdsTagColor.success, - child: const Text('Approved'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - filled: true, - customColor: ZdsColors.blueGrey, - child: const Text('Custom onClose'), - onClose: () {}, - ), - ), - // The following two tags are meant to show tags that enable users' big font settings - const ZdsListTile( - trailing: ZdsTag( - unrestrictedSize: true, - child: Text('Unbounded'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - unrestrictedSize: true, - onClose: () {}, - child: const Text('Unbound+btn'), - ), - ), - // New Tag variants from https://jira.zebra.com/browse/ZU-92 - 30/03/2022 J - ZdsListTile( - trailing: ZdsTag( - rectangular: true, - color: ZdsTagColor.secondary, - child: const Text('Give away'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - rectangular: true, - color: ZdsTagColor.secondary, - child: const Text('Additional'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - rectangular: true, - color: ZdsTagColor.success, - prefix: const Icon(Icons.check, size: 18), - child: const Text('Approved'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - rectangular: true, - color: ZdsTagColor.secondary, - prefix: const Icon(Icons.hourglass_bottom, size: 18), - child: const Text('Pending'), - ), - ), - ZdsListTile( - trailing: ZdsTag( - rectangular: true, - color: ZdsTagColor.error, - prefix: const Icon(Icons.close, size: 18), - child: const Text('Declined'), - ), - ), - ], + body: ZdsList( + children: [ + ZdsCard( + padding: EdgeInsets.zero, + child: const ZdsListTile( + trailing: ZdsTag( + child: Text('Incomplete'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + color: ZdsTagColor.primary, + child: const Text('Pending Review'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rounded: true, + prefix: const Text('U'), + color: ZdsTagColor.error, + child: const Text('Urgent'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rounded: true, + prefix: const Text('1'), + color: ZdsTagColor.alert, + child: const Text('High Priority'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rounded: true, + prefix: const Text('2'), + color: ZdsTagColor.secondary, + child: const Text('Medium Priority'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rounded: true, + prefix: const Text('3'), + color: ZdsTagColor.success, + child: const Text('Low Priority'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: const ZdsListTile( + trailing: ZdsTag( + filled: true, + child: Text('Default'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + filled: true, + color: ZdsTagColor.error, + child: const Text('Urgent'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + filled: true, + color: ZdsTagColor.alert, + child: const Text('High Priority'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: const ZdsListTile( + trailing: ZdsTag( + filled: true, + child: Text('Primary'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + filled: true, + color: ZdsTagColor.primary, + child: const Text('Medium Priority'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + filled: true, + color: ZdsTagColor.success, + child: const Text('Approved'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + filled: true, + customColor: zetaColors.cool, + child: const Text('Custom onClose'), + onClose: () {}, + ), + ), + ), + // The following two tags are meant to show tags that enable users' big font settings + ZdsCard( + padding: EdgeInsets.zero, + child: const ZdsListTile( + trailing: ZdsTag( + unrestrictedSize: true, + child: Text('Unbounded'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + unrestrictedSize: true, + onClose: () {}, + child: const Text('Unbound+btn'), + ), + ), + ), + // New Tag variants from https://jira.zebra.com/browse/ZU-92 - 30/03/2022 J + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rectangular: true, + color: ZdsTagColor.secondary, + child: const Text('Give away'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rectangular: true, + color: ZdsTagColor.secondary, + child: const Text('Additional'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rectangular: true, + color: ZdsTagColor.success, + prefix: Icon(Icons.check, size: 18, color: zetaColors.green), + child: const Text( + 'Approved', + ), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rectangular: true, + color: ZdsTagColor.secondary, + prefix: Icon(Icons.hourglass_bottom, size: 18, color: Theme.of(context).colorScheme.secondary), + child: const Text('Pending'), + ), + ), + ), + ZdsCard( + padding: EdgeInsets.zero, + child: ZdsListTile( + trailing: ZdsTag( + rectangular: true, + color: ZdsTagColor.error, + prefix: Icon(Icons.close, size: 18, color: zetaColors.red), + child: const Text('Declined'), + ), + ), ), - ), + ].divide(const SizedBox(height: 16)).toList(), ), ); } diff --git a/example/lib/pages/components/tag_list.dart b/example/lib/pages/components/tag_list.dart index abe48f6..23831d1 100644 --- a/example/lib/pages/components/tag_list.dart +++ b/example/lib/pages/components/tag_list.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class TagListDemo extends StatelessWidget { diff --git a/example/lib/pages/components/text_field.dart b/example/lib/pages/components/text_field.dart index 601ac25..38b5f72 100644 --- a/example/lib/pages/components/text_field.dart +++ b/example/lib/pages/components/text_field.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class TextFieldDemo extends StatefulWidget { @@ -12,6 +13,7 @@ class _TextFieldDemoState extends State { String? error; final noteController = TextEditingController(); String? dropdownVal; + @override void initState() { noteController.text = 'Lets get an early jump on the seasonal plannogram for this week. for this week.'; @@ -32,6 +34,7 @@ class _TextFieldDemoState extends State { ), const SizedBox(height: 16), ZdsDropdownList( + label: 'Dropdown label', options: [ ZdsDropdownListItem(name: 'Approved', value: 'A'), ZdsDropdownListItem(name: 'Pending', value: 'P'), @@ -50,6 +53,7 @@ class _TextFieldDemoState extends State { const SizedBox(height: 20), ZdsCard( child: ZdsResizableTextArea( + enabled: false, controller: noteController, label: 'Responder Notes', maxLines: 100, @@ -73,17 +77,18 @@ class _TextFieldDemoState extends State { labelText: 'Edit Filter Name', counterText: 'Character left: 255', ), - ), + ).paddingOnly(bottom: 16), TextField( maxLines: 10, decoration: ZdsInputDecoration( labelText: 'Message', counterText: 'Character left: 255', ), - ), + ).paddingOnly(bottom: 16), TextFormField( initialValue: 'Weekly Task', decoration: ZdsInputDecoration( + mandatory: true, labelText: 'Title', ), ), @@ -109,10 +114,15 @@ class _TextFieldDemoState extends State { ].divide(const SizedBox(width: 10)).toList(), ), TextFormField( - decoration: ZdsInputDecoration.withNoLabel(errorText: error), + decoration: ZdsInputDecoration.withNoLabel( + prefixIcon: Icon(Icons.verified_user), + suffixIcon: Icon(Icons.chevron_right), + ), ), TextFormField( - decoration: ZdsInputDecoration.withNoLabel(), + decoration: ZdsInputDecoration.withNoLabel( + errorText: error, + ), ), ZdsButton.muted( child: const Text('Validate'), diff --git a/example/lib/pages/components/toast.dart b/example/lib/pages/components/toast.dart index 939af4e..b47d1f3 100644 --- a/example/lib/pages/components/toast.dart +++ b/example/lib/pages/components/toast.dart @@ -13,72 +13,62 @@ class _ToastDemoState extends State { @override Widget build(BuildContext context) { - return SafeArea( - top: false, - child: Scaffold( - appBar: AppBar(), - body: SizedBox.expand( - child: Column( - children: [ - ZdsButton.muted( - child: const Text('green toast'), - onTap: () { - showToast(context, color: ZdsToastColors.success); - }, - ), - ZdsButton( - isDangerButton: true, - child: const Text('red toast'), - onTap: () { - showToast(context, color: ZdsToastColors.error); - }, - ), - ZdsButton( - child: const Text('blue toast'), - onTap: () { - showToast(context, color: ZdsToastColors.primary); - }, - ), - ZdsButton.muted( - child: const Text('orange toast'), - onTap: () { - showToast(context, color: ZdsToastColors.warning); - }, - ), - ZdsButton.muted( - child: const Text('longer toast'), - onTap: () { - showLongerToast( - context, - ); - }, - ), - ZdsButton.muted( - child: const Text('Dark toast'), - onTap: () { - showToast(context, color: ZdsToastColors.dark); - }, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Show persistent toast'), - Switch(value: showPersistentToast, onChanged: (bool b) => setState(() => showPersistentToast = b)), - ], - ), - ].divide(const SizedBox(height: 10)).toList(), - ), - ), - bottomNavigationBar: PreferredSizeColumn( + return Scaffold( + appBar: AppBar(), + body: SingleChildScrollView( + padding: EdgeInsets.all(14), + child: Column( children: [ - if (showPersistentToast) - const ZdsToast( - rounded: false, - title: Text('Persistent default toast'), - ), - ], + ZdsButton.muted( + child: const Text('green/positive toast'), + onTap: () => showToast(context, color: ZdsToastColors.success), + ), + ZdsButton( + isDangerButton: true, + child: const Text('red/negative toast'), + onTap: () => showToast(context, color: ZdsToastColors.error), + ), + ZdsButton.muted( + child: const Text('orange/warning toast'), + onTap: () => showToast(context, color: ZdsToastColors.warning), + ), + ZdsButton.muted( + child: const Text('purple/info toast'), + onTap: () => showToast(context, color: ZdsToastColors.info), + ), + ZdsButton( + child: const Text('primary toast'), + onTap: () => showToast(context, color: ZdsToastColors.primary), + ), + ZdsButton.muted( + child: const Text('longer toast'), + onTap: () => showLongerToast(context), + ), + ZdsButton.muted( + child: const Text('Dark toast'), + onTap: () => showToast(context, color: ZdsToastColors.dark), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Show persistent toast'), + Switch(value: showPersistentToast, onChanged: (bool b) => setState(() => showPersistentToast = b)), + ], + ), + ].divide(const SizedBox(height: 10)).toList(), ), ), + bottomNavigationBar: showPersistentToast + ? SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: ZdsToast( + rounded: false, + title: Text('Persistent default toast'), + ), + ), + ) + : null, ); } diff --git a/example/lib/pages/components/toolbar.dart b/example/lib/pages/components/toolbar.dart index d6d9301..b0e4c1b 100644 --- a/example/lib/pages/components/toolbar.dart +++ b/example/lib/pages/components/toolbar.dart @@ -13,33 +13,31 @@ class _ToolBarDemoState extends State { @override Widget build(BuildContext context) { + final zetaColors = Zeta.of(context).colors; return Scaffold( - appBar: AppBar( - elevation: 0, - ), + appBar: AppBar(elevation: 0), body: SingleChildScrollView( child: Column( children: [ ZdsToolbar( - title: DateRange( + title: ZdsDateRange( emptyLabel: 'Select range', isWeekMode: true, actions: [ ZdsButton.text( - child: Text(' View', style: TextStyle(color: Theme.of(context).colorScheme.onPrimary)), + child: Text(' View'), onTap: () {}, ), ], ), ), ZdsToolbar( - title: DateRange( + backgroundColor: zetaColors.iconDefault, + title: ZdsDateRange( emptyLabel: 'Select range', isSelectable: false, initialDateRange: r, - onChange: (r1) { - setState(() => r = r1); - }, + onChange: (r1) => setState(() => r = r1), actions: [ ZdsButton.text( child: Text('Fiscal View', style: TextStyle(color: Theme.of(context).colorScheme.onPrimary)), @@ -48,9 +46,9 @@ class _ToolBarDemoState extends State { ], ), ), - const SizedBox(height: 80), ZdsToolbar( - title: DateRange( + backgroundColor: zetaColors.primary, + title: ZdsDateRange( emptyLabel: 'Select range', initialDateRange: r, onChange: (r1) => setState(() => r = r1), @@ -89,17 +87,17 @@ class _ToolBarDemoState extends State { ), ), ZdsToolbar( - backgroundColor: Theme.of(context).colorScheme.surface, - title: DateRange( - textStyle: Theme.of(context) - .textTheme - .titleSmall! - .copyWith(fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.primary), + backgroundColor: zetaColors.yellow.surface, + title: ZdsDateRange( + textStyle: Theme.of(context).textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w500, + color: zetaColors.yellow.selected, + ), initialDateRange: DateTimeRange( start: DateTime(2022, 05, 12), end: DateTime(2022, 05, 18), ), - isSelectable: false, + //isSelectable: false, ), ), ZdsToolbar( @@ -112,7 +110,7 @@ class _ToolBarDemoState extends State { ), ], child: Container( - color: Theme.of(context).colorScheme.primary, + color: Theme.of(context).colorScheme.surfacePrimary, height: 400, ), ), diff --git a/example/lib/pages/components/vertical_nav.dart b/example/lib/pages/components/vertical_nav.dart index d5e24a3..8b80a0b 100644 --- a/example/lib/pages/components/vertical_nav.dart +++ b/example/lib/pages/components/vertical_nav.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:zds_flutter/zds_flutter.dart'; class VerticalNavDemo extends StatefulWidget { @@ -75,11 +76,14 @@ class _VerticalNavDemoState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ verticalNav, - SizedBox( - height: 500, - child: verticalNav, + Expanded( + child: Center( + child: SizedBox( + height: 500, + child: verticalNav, + ), + ), ), - const SizedBox(), ], ), ); diff --git a/example/lib/pages/html_view.dart b/example/lib/pages/html_view.dart new file mode 100644 index 0000000..b700d70 --- /dev/null +++ b/example/lib/pages/html_view.dart @@ -0,0 +1,782 @@ +import 'package:flutter/material.dart'; +import 'package:zds_flutter/zds_flutter.dart'; + +const mediaHtml = ''' + + + + + Notes + + + + + + + + + + +

Media audio url:

+
+
+
+
+
+ +

Media video Url:

+
+
+
+
+
+ +

Links:

+

https://google.com

+

https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4

+

+ + + + +'''; + +const html = ''' + + + + + Notes + + + + + + +
+

 

 

 

 

 

 

 

 

 

 

 

 

 

Bold : Retail describes the sale of a product or service to an individual consumer for personal use. I

talic: The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. Underline: The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

 

Bold Italic Underline : Retail describes the sale of a product or service to an individual consumer for personal use.The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

 

Retail describes the sale of a product or service to an individual consumer for personal use.The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

Retail describes the sale of a product or service to an individual consumer for personal use.The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

 

Retail describes the sale of a product or service to an individual consumer for personal use.The transaction itself can occur through a number of different sales channels, such as online, in a brick-and-mortar storefront, through direct sales, or direct mail. The aspect of the sale that qualifies it as a retail transaction is that the end user is the buyer.

 

  • Hardlines: things that tend to last a long time, such as appliances, cars, and furniture
  • Soft goods or consumables: things like clothing, shoes, and toiletries
  • Food: things like meat, cheese, produce, and baked goods
  • Art: things like fine art, as well as books and musical instruments

 

Within those categories you’ll also find different types of retail stores. Some of the most common types include:

HTML:
 

+
Column1Column2Column3Column4Column5Column6Column7
Col1Row1Col2Row1Col3Row1Col4Row1Col5Row1Col6Row1
Col1Row2Col2Row2Col3Row2Col4Row2Col5Row2Col6Row2 
Col1Row3Col2Row3Col3Row3Col4Row3Col5Row3Col6Row3
Col1Row4Col2Row4Col3Row4Col4Row4Col5Row4Col6Row4 
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Column1Column2Column3Column4Column5Column6Column7
+

Col1Row1

+

Col2Row1

+
Col3Row1Col4Row1Col5Row1 +

Col6Row1

+

Col6Row2

+
Col1Row2 +

Col2Row2

+

Col2Row3

+
+

Col3Row2

+

Col4Row2

+
Col5Row2
Col1Row3Col3Row3Col4Row3Col5Row3Col6Row3
Col1Row4Col2Row4Col3Row4Col4Row4Col5Row4Col6Row4
+
+

+ 1. This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. + 2.This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. + 3. This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. + 4. This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. + 5. This paragraph has multiple lines. + But HTML reduces them to a single line, + omitting the carriage return we have used. +

+

+ This paragraph has multiple spaces. + But HTML reduces them all to a single + space, omitting the extra spaces and line we have used. +

+ + +

Links: 

https://google.com

https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4

 

 

 

 

Media audio url:

 

 

 

Media video Url:

 

 

iframe/embedded video

 

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Column1Column2Column3Column4Column5Column6Column7
Col1Row1Col2Row1Col3Row1Col4Row1Col5Row1Col6Row1
Col1Row2Col2Row2Col3Row2Col4Row2Col5Row2Col6Row2 
Col1Row3Col2Row3Col3Row3Col4Row3Col5Row3Col6Row3
Col1Row4Col2Row4Col3Row4Col4Row4Col5Row4Col6Row4 
+
+ + + + '''; + +const imgHtml = ''' + + + + + Notes + + + + + + +
+ +

What Is Retail?

+

Definitions & Examples of Retail

+

By

+

Barbara Farfan

+

Barbara Farfan

+

Barbara Farfan has 20 years of experience as a business consultant in the retail industry.

+

LEARN ABOUT OUR EDITORIAL POLICIES

+

Updated on November 29, 2022

+

Reviewed by David Kindness

+

Customer looking at mens accessories with shop owner in mens boutique

+

PHOTO: THOMAS BARWICK / GETTY IMAGES

+

Retail is a very broad term that encompasses a huge industry, employing millions of people and generating trillions of dollars per year in sales revenue. Retail is the sale of goods to consumers—not for them to sell, but for use and consumption by the purchaser.

+

This knowledge can help you gain an understanding of the processes involved in getting merchandise to the shelves and the effect a supply chain can have on pricing and sales.

+

What Is Retail?

+

Retail involves the sale of merchandise from a single point of purchase directly to a customer who intends to use that product. The single point of purchase could be a brick-and-mortar retail store, an internet shopping website, or a catalog.

+

Retailing is all about attracting consumers through product displays and marketing. Inventory must be kept, shelves must be kept full, and payments have to be collected. Retailers are more than places to purchase merchandise, however—they provide manufacturers an outlet so that they can focus on creating their products.

+

Note

+

In essence, retailing is the culmination of many different processes brought together to create sales.

+

How Does Retailing Work?

+

Retailers rely on a system that supplies them with merchandise to market to consumers. To acquire inventory and ensure they have the products they want to sell, relationships must be established with businesses that operate within the retail supply chain.

+

 

+

The retail supply chain consists of manufacturers, wholesalers, retailers, and the consumer (end-user). The wholesaler is directly connected to the manufacturer, while the retailer is connected to the wholesaler.

+

The roles of the key players in a typical retail supply chain are:

+
+
    +
  • Manufacturers: Produce goods using machines, raw materials, and labor
  • +
  • Wholesalers: Purchase finished goods from the manufacturers and sell those goods to retailers in large bulk quantities
  • +
  • Retailers: Sell the goods in small quantities to the end-user at a higher price, theoretically at the manufacturers suggested retail price
  • +
  • Consumers: Buy the goods from the retailer for personal use
  • +
+ +

List support:

+
    +
  1. This
  2. +
  3. is

  4. +
  5. an
  6. +
  7. + ordered +
      +
    • With

      ...
    • +
    • a
    • +
    • nested
    • +
    • unordered +
        +
      1. With a nested
      2. +
      3. ordered list
      4. +
      5. with a lower alpha list style
      6. +
      7. starting at letter e
      8. +
      +
    • +
    • list
    • +
    +
  8. +
  9. list! Lorem ipsum dolor sit amet.
  10. +
  11. Header 2

  12. +

  13. Header 2
  14. +
+

retail supply chain

+
+ + + + '''; +const tableHtml = ''' + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
qwerq
+ 2132312 + + + 1231wef + + 123456 + + 12345 + + 12345 + +
    +
  • 123
  • +
  • 1243
  • +
+
123
123 +
    +
  1. 12345
  2. +
  3. 32435
  4. +
+
+ 213 + +

12345

+
+ 213 + +
+

12345

+
+
+ 213 + +
12345678
+
ksdlkjhs dajflh +

123

+
+ 213 +
231
+

1231232basdvc ns/,vn d

+

vd vdfsbv'dsfv

+

a vb;sdf vbsd; vbfd; vbj

+
+
+ +

Styled Complex/Nested Table

+ + + + + + + + + + + + + + + + + + +
Caption-Nested Table
Column 1Column 2
Colspan Column
Rowspan CellCell 2
+ + + + + + + + + +
Inner Column Heading 1Inner Column Heading 2
Inner Data Cell 1 + + + + + + + + + +
Inner Most Column Heading 1Inner Most Column Heading 2
Innermost Data Cell 1Innermost Data Cell 2
+ +
+
+ +

No style Nested table

+
 
 

paragraphs

 

words

 

bytes

 

lists

 

Start with 'Lorem
ipsum dolor sit amet...'

  
+ + + + '''; + +const htmlData = r""" +

Scroll to bottom

+

Header 1

+

Header 2

+

Header 3

+

Header 4

+
Header 5
+
Header 6
+ +

Inline Styles:

+

The should be BLUE style='color: blue;'

+

The should be RED style='color: red;'

+

The should be BLACK with 10% alpha style='color: rgba(0, 0, 0, 0.10);

+

The should be GREEN style='color: rgb(0, 97, 0);

+

The should be GREEN style='color: rgb(0, 97, 0);

+ +

Text Alignment

+

Center Aligned Text

+

Right Aligned Text

+

Justified Text

+

Center Aligned Text

+ +

Margins

+
Default Div (width 350px height 20px)
+
margin-left: 3em
+
margin: auto
+
margin: 15px auto
+
margin-left: auto
+
margin-right: auto
+
margin-left: auto; margin-right: 3em
+ +

Margin Auto on Image

+

display:inline-block; margin: auto; (should not center):

+ +

display:block margin: auto; (should center):

+ + +

Support for sub/sup

+ Solve for xn: log2(x2+n) = 93 +

One of the most common equations in all of physics is
E=mc2.

+ +

Ruby Support:

+

+ + 漢かん + 字 + +  is Japanese Kanji. +

+ +

Support for maxLines:

+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vestibulum sapien feugiat lorem tempor, id porta orci elementum. Fusce sed justo id arcu egestas congue. Fusce tincidunt lacus ipsum, in imperdiet felis ultricies eu. In ullamcorper risus felis, ac maximus dui bibendum vel. Integer ligula tortor, facilisis eu mauris ut, ultrices hendrerit ex. Donec scelerisque massa consequat, eleifend mauris eu, mollis dui. Donec placerat augue tortor, et tincidunt quam tempus non. Quisque sagittis enim nisi, eu condimentum lacus egestas ac. Nam facilisis luctus ipsum, at aliquam urna fermentum a. Quisque tortor dui, faucibus in ante eget, pellentesque mattis nibh. In augue dolor, euismod vitae eleifend nec, tempus vel urna. Donec vitae augue accumsan ligula fringilla ultrices et vel ex.
+ + +

Table support (With custom styling!):

+ + + + + + + + + + + + + + + + + + + +
OneTwoThree
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
Rowspan
DataData
+For 50 years, WWF has been protecting the future of nature. +
fDatafDatafData
+ +

List support:

+
    +
  1. This
  2. +
  3. is

  4. +
  5. an
  6. +
  7. + ordered +
      +
    • With

      ...
    • +
    • a
    • +
    • nested
    • +
    • unordered +
        +
      1. With a nested
      2. +
      3. ordered list
      4. +
      5. with a lower alpha list style
      6. +
      7. starting at letter e
      8. +
      +
    • +
    • list
    • +
    +
  8. +
  9. list! Lorem ipsum dolor sit amet.
  10. +
  11. Header 2

  12. +

  13. Header 2
  14. +
+ +

Link support:

+

+ Linking to websites has never been easier. +

+ +

Image support:

+ + + + + + + + + +
Network pngxkcd
Local asset png
Local asset svg
Data uri (with base64 support)Red dot (png) + Green dot (base64 svg) + Green dot (plain svg) +
Custom image render
Broken network imageBroken network image alt text
+ +

SVG support:

+ + + + + + +

Custom Element Support:

+ Inline: <bird></bird> becomes: . +
+ + Block: <flutter></flutter> becomes: + + and <flutter horizontal></flutter> becomes: + + +

MathML Support:

+ + + x + = + + + + - + b + + ± + + + + b + 2 + + - + + 4 + + a + + c + + + + + + 2 + + a + + + + + + + + 0 + 5 + + + x + 2 + + + dx + = + [ + + 1 + 3 + + + x + 3 + + + ] + 0 + 5 + + = + + 125 + 3 + + - + 0 + = + + 125 + 3 + + +
+ + + sin + 2 + + θ + + + + cos + 2 + + θ + = + 1 + + +

Tex Support with the custom tex tag:

+ i\hbar\frac{\partial}{\partial t}\Psi(\vec x,t) = -\frac{\hbar}{2m}\nabla^2\Psi(\vec x,t)+ V(\vec x)\Psi(\vec x,t) +

blockquote:

+
+For 50 years, WWF has been protecting the future of nature. The world's leading conservation organization, WWF works in 100 countries and is supported by 1.2 million members in the United States and close to 5 million globally. +
+

Scroll to top

+"""; + +const testHtml = ''' +

 

Heading1 

Heading 2

Heading 3

Heading 4

Heading 2
Heading 2

 

Bold : 

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

Italic : 

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

Italic

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

 

Scratch

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

 

X2

56565676756566656

 

Left Align: 

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

Right Align: 

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

 

Center Align: 

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

 

Justify Align: 

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

 

Font: 

Comic: Lorem ipsum dolor sit amet, consectetur adipiscing elit, 

Courier new: sed do eiusmod tempor incididunt ut labore et dolore magna aliqua

Georgia: Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat

Verdana: Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

Font Size

Comic: Lorem ipsum dolor sit amet, consectetur adipiscing elit, 

Courier new: sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 

Georgia: Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat

Verdana: Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

Color:

Red: Lorem ipsum dolor sit amet, consectetur adipiscing elit

Purple: sed do eiusmod tempor incididunt ut labore et dolore magna aliqua

Yellow: Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur Blue: sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

Color Background

Orange: nm,fnv,mnbgmbnmm

Red: Duis aute irure dolor in reprehenderit

Purple: Duis aute irure dolor in reprehenderit

Yellow: Duis aute irure dolor in reprehenderit

 

 

List-Disc

  • Purple: Duis aute irure dolor in reprehenderit'
  • Purple: Duis aute irure dolor in reprehenderit
  • Purple: Duis aute irure dolor in reprehenderit
  • Purple: Duis aute irure dolor in reprehenderit
  • Purple: Duis aute irure dolor in reprehenderit

 

List-Circle

  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit

 

List - Square

  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit
  • Duis aute irure dolor in reprehenderit

 

List-Number

  1. Duis aute irure dolor in reprehenderit
  2. Duis aute irure dolor in reprehenderit
  3. Duis aute irure dolor in reprehenderit
  4. Duis aute irure dolor in reprehenderit
  5. Duis aute irure dolor in reprehenderit
  6. Duis aute irure dolor in reprehenderit

 

List - Alpha

  1. Duis aute irure dolor in reprehenderit
  2. Duis aute irure dolor in reprehenderit
  3. Duis aute irure dolor in reprehenderit
  4. Duis aute irure dolor in reprehenderit
  5. Duis aute irure dolor in reprehenderit
  6. Duis aute irure dolor in reprehenderit

Blockquote:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 

+ + +Page Title + + + +

This is a Heading

+

This is a paragraph.

+ + +

 

Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1

Test Row Merge

Test Row Merge

Test Column Merge

Test Column Merge

Txt with Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

List-Numbered

  1. Test1
  2. tes2

List - Disc

  • test 1
  • test 2
Bold  Italic Underline Scratch123451234
       
        
        
        

Link:

https://zebra.com

 

Media: Audio

Media: Video

 

'''; + +class HtmlPreview extends StatelessWidget { + const HtmlPreview({super.key}); + + @override + Widget build(BuildContext context) { + final htmlList = [tableHtml, mediaHtml, html, htmlData, testHtml, imgHtml]; + return Scaffold( + backgroundColor: Theme.of(context).colorScheme.surface, + appBar: AppBar( + title: const Text('Html Preview'), + ), + body: ListView.separated( + itemBuilder: (BuildContext context, int index) { + final data = htmlList[index]; + return ZdsHtmlContainer( + data, + showReadMore: false, + ); + }, + itemCount: htmlList.length, + padding: EdgeInsets.zero, + separatorBuilder: (BuildContext context, int index) => + const Divider(thickness: 2).paddingOnly(bottom: 10, top: 10), + ), + // SingleChildScrollView(child: ZdsHtmlContainer(mediaHtml, containerWidth: MediaQuery.of(context).size.width,)), + ); + } +} diff --git a/example/lib/pages/quill_editor_demo.dart b/example/lib/pages/quill_editor_demo.dart new file mode 100644 index 0000000..f64492d --- /dev/null +++ b/example/lib/pages/quill_editor_demo.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:zds_flutter/zds_flutter.dart'; + +///Example for htmlEditor +class QuillEditorDemo extends StatefulWidget { + const QuillEditorDemo({super.key}); + + @override + State createState() => _QuillEditorDemoState(); +} + +class _QuillEditorDemoState extends State { + final controller = QuillController.basic(); + + @override + void initState() { + super.initState(); + ZdsQuillDelta.fromHtml(''' +

H1 heading

H2 Heading

H3 Heading

Normal
Because

+ ''').then((value) { + controller.document = value.document; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Quill Editor'), + actions: [ + IconButton( + icon: const Icon(Icons.html), + onPressed: () { + showDialog( + context: context, + builder: (context) { + return ConstrainedBox( + constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.7), + child: Dialog( + child: ZdsCard( + child: Text(ZdsQuillDelta(document: controller.document).toHtml()), + ), + ), + ); + }, + ); + }, + ), + ], + ), + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.edit), + onPressed: () { + ZdsQuillEditorPage.edit( + context, + title: 'Edit Notes', + initialDelta: ZdsQuillDelta(document: controller.document), + charLimit: 20000, + ).then((value) { + if (value != null) { + controller.document = value.document; + } + }); + }, + ), + body: Column( + children: [ + Expanded( + child: QuillEditor.basic( + padding: const EdgeInsets.all(16), + controller: controller, + focusNode: FocusNode(canRequestFocus: false), + readOnly: true, + ), + ), + ], + ), + ); + } +} diff --git a/example/lib/pages/theme/colors.dart b/example/lib/pages/theme/colors.dart index 66cb21c..226a5a6 100644 --- a/example/lib/pages/theme/colors.dart +++ b/example/lib/pages/theme/colors.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:zds_flutter/zds_flutter.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; class ColorExample { final String name; @@ -25,12 +24,12 @@ class ColorsDemo extends StatelessWidget { { 'color': Theme.of(context).colorScheme.primary, 'name': 'Primary', - 'subtitle': 'Theme.of(context).colorScheme.primary', + 'subtitle': 'Zeta.of(context).colors.primary | Theme.of(context).colorScheme.primary', }, { 'color': Theme.of(context).colorScheme.secondary, 'name': 'Secondary', - 'subtitle': 'Theme.of(context).colorScheme.secondary', + 'subtitle': 'Zeta.of(context).colors.secondary | Theme.of(context).colorScheme.secondary', }, { 'color': Theme.of(context).colorScheme.primaryContainer, @@ -43,55 +42,7 @@ class ColorsDemo extends StatelessWidget { 'subtitle': 'Theme.of(context).colorScheme.secondaryContainer', }, ]; - final List> greys = [ - { - 'color': ZdsColors.black, - 'name': 'Black', - 'subtitle': 'ZdsColors.black', - }, - { - 'color': ZdsColors.darkGrey, - 'name': 'Grey 1', - 'subtitle': 'ZdsColors.darkGrey', - }, - { - 'color': ZdsColors.blueGrey, - 'name': 'Grey 2', - 'subtitle': 'ZdsColors.blueGrey', - }, - { - 'color': ZdsColors.lightGrey, - 'name': 'Grey 3', - 'subtitle': 'ZdsColors.lightGrey', - }, - { - 'color': ZdsColors.white, - 'name': 'White', - 'subtitle': 'ZdsColors.white', - }, - ]; - final otherColors = [ - { - 'color': ZdsColors.red, - 'name': 'Red', - 'subtitle': 'ZdsColors.red', - }, - { - 'color': ZdsColors.green, - 'name': 'Green', - 'subtitle': 'ZdsColors.green', - }, - { - 'color': ZdsColors.yellow, - 'name': 'Yellow', - 'subtitle': 'ZdsColors.yellow', - }, - { - 'color': ZdsColors.orange, - 'name': 'Orange', - 'subtitle': 'ZdsColors.orange', - }, - ]; + final theme = [ { 'color': Theme.of(context).colorScheme.primary, @@ -164,8 +115,43 @@ class ColorsDemo extends StatelessWidget { 'subtitle': 'Theme.of(context).colorScheme.onError', }, ]; + final List> greys = [ + { + 'color': Zeta.of(context).colors.black, + 'name': 'Black', + 'subtitle': 'Zeta.of(context).colors.black', + }, + { + 'color': Zeta.of(context).colors.white, + 'name': 'White', + 'subtitle': 'Zeta.of(context).colors.white', + }, + ]; + final alertColors = [ + { + 'color': Zeta.of(context).colors.positive, + 'name': 'Positive', + 'subtitle': 'Zeta.of(context).colors.positive', + }, + { + 'color': Zeta.of(context).colors.negative, + 'name': 'Negative', + 'subtitle': 'Zeta.of(context).colors.negative', + }, + { + 'color': Zeta.of(context).colors.warning, + 'name': 'Warning', + 'subtitle': 'Zeta.of(context).colors.warning', + }, + { + 'color': Zeta.of(context).colors.info, + 'name': 'Info', + 'subtitle': 'Zeta.of(context).colors.info', + }, + ]; - final List zeta = ZetaColors.of(context).rainbow.map((e) => ColorSwatchExample(e, '')).toList(); + final List zeta = + Zeta.of(context).colors.rainbow.map((e) => ColorSwatchExample(e, '')).toList(); return LayoutBuilder( builder: (context, constraints) { @@ -173,16 +159,15 @@ class ColorsDemo extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('ZDS Colors', style: Theme.of(context).textTheme.displayLarge).paddingOnly(left: 16), - _ColorRow(colors: primaryColors, title: 'Theme colors'), + _ColorRow(colors: theme, title: 'Theme colors'), + _ColorRow(colors: primaryColors, title: 'Primary colors'), _ColorRow(colors: greys, title: 'Greys'), - _ColorRow(colors: otherColors, title: 'Other colors'), + _ColorRow(colors: alertColors, title: 'Alert colors'), const _PrimarySwatches(), const _OtherSwatches(), - _ColorRow(colors: theme, title: 'All theme ColorScheme colors'), - const _Spacer(), const _Spacer(), Text('Zeta Colors', style: Theme.of(context).textTheme.displayLarge).paddingOnly(left: 16), + const _Spacer(), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( @@ -234,11 +219,11 @@ class _ColorBoxZeta extends StatelessWidget { children: [ Text( text, - style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: computeForeground(color)), + style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: color.onColor), ), Text( color.toHexNoAlpha().toUpperCase(), - style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: computeForeground(color)), + style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: color.onColor), ), ], ).padding(16), @@ -251,6 +236,36 @@ class _OtherSwatches extends StatelessWidget { @override Widget build(BuildContext context) { + final swatches = [ + { + 'key': 'Red', + 'value': Zeta.of(context).colors.red, + }, + { + 'key': 'Orange', + 'value': Zeta.of(context).colors.orange, + }, + { + 'key': 'Yellow', + 'value': Zeta.of(context).colors.yellow, + }, + { + 'key': 'Green', + 'value': Zeta.of(context).colors.green, + }, + { + 'key': 'Blue', + 'value': Zeta.of(context).colors.blue, + }, + { + 'key': 'Teal', + 'value': Zeta.of(context).colors.teal, + }, + { + 'key': 'Pink', + 'value': Zeta.of(context).colors.pink, + }, + ]; return Column( children: [ const _Spacer(), @@ -269,29 +284,26 @@ class _OtherSwatches extends StatelessWidget { child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _Spacer(), - _Swatch( - swatch: ZdsColors.redSwatch, - values: [ - {'val': 'fair', 'display': 'fair'}, - {'val': 'light', 'display': 'light'}, - {'val': 'medium', 'display': 'medium'}, - {'val': 'dark', 'display': 'dark'}, - ], - headColor: ZdsColors.red, - headText: 'Red', - ), - _Spacer(), - _Swatch( - swatch: ZdsColors.greenSwatch, - values: [ - {'val': 'light', 'display': 'light'}, - {'val': 'medium', 'display': 'medium'}, - {'val': 'dark', 'display': 'dark'}, - ], - headColor: ZdsColors.green, - headText: 'Green', - ), + for (final swatch in swatches) ...[ + _Spacer(), + _Swatch( + swatch: swatch['value'] as ZetaColorSwatch, + values: [ + {'val': 10, 'display': '10'}, + {'val': 20, 'display': '20'}, + {'val': 30, 'display': '30'}, + {'val': 40, 'display': '40'}, + {'val': 50, 'display': '50'}, + {'val': 60, 'display': '60'}, + {'val': 70, 'display': '70'}, + {'val': 80, 'display': '80'}, + {'val': 90, 'display': '90'}, + {'val': 100, 'display': '100'}, + ], + headColor: swatch['value'] as ZetaColorSwatch, + headText: swatch['key'] as String, + ), + ], _Spacer(), ], ), @@ -327,36 +339,30 @@ class _PrimarySwatches extends StatelessWidget { children: [ const _Spacer(), _Swatch( - swatch: ZdsColors.primarySwatch(context), - values: List.generate(9, (i) => {'val': (i + 1) * 100, 'display': '${(i + 1) * 10}%'}), + swatch: Zeta.of(context).colors.primary, + values: List.generate(10, (i) => {'val': (i + 1) * 10, 'display': '${(i + 1) * 10}%'}), headColor: Theme.of(context).colorScheme.primary, headText: 'Primary', ), const _Spacer(), _Swatch( - swatch: ZdsColors.secondarySwatch(context), - values: List.generate(9, (i) => {'val': (i + 1) * 100, 'display': '${(i + 1) * 10}%'}), + swatch: Zeta.of(context).colors.secondary, + values: List.generate(10, (i) => {'val': (i + 1) * 10, 'display': '${(i + 1) * 10}%'}), headColor: Theme.of(context).colorScheme.secondary, headText: 'Secondary', ), const _Spacer(), _Swatch( - swatch: ZdsColors.greyWarmSwatch, - values: [ - const {'val': 50, 'display': 50}, - ...List.generate(12, (i) => {'val': (i + 1) * 100, 'display': (i + 1) * 100}) - ], - headColor: ZdsColors.darkGrey, + swatch: Zeta.of(context).colors.warm, + values: List.generate(10, (i) => {'val': (i + 1) * 10, 'display': '${(i + 1) * 10}%'}), + headColor: Zeta.of(context).colors.warm, headText: 'Warm grey', ), const _Spacer(), _Swatch( - swatch: ZdsColors.greyCoolSwatch, - values: [ - const {'val': 50, 'display': 50}, - ...List.generate(12, (i) => {'val': (i + 1) * 100, 'display': (i + 1) * 100}) - ], - headColor: ZdsColors.blueGrey, + swatch: Zeta.of(context).colors.cool, + values: List.generate(10, (i) => {'val': (i + 1) * 10, 'display': '${(i + 1) * 10}%'}), + headColor: Zeta.of(context).colors.cool, headText: 'Cool grey', ), const _Spacer(), @@ -373,6 +379,7 @@ class _PrimarySwatches extends StatelessWidget { class _ColorRow extends StatelessWidget { final List> colors; final String title; + const _ColorRow({Key? key, required this.colors, required this.title}) : super(key: key); @override @@ -426,6 +433,7 @@ class _ColorBox extends StatelessWidget { final Color color; final String text; final String subtitle; + const _ColorBox({Key? key, required this.color, required this.text, required this.subtitle}) : super(key: key); @override @@ -440,15 +448,15 @@ class _ColorBox extends StatelessWidget { children: [ Text( text, - style: Theme.of(context).textTheme.displaySmall?.copyWith(color: computeForeground(color)), + style: Theme.of(context).textTheme.displaySmall?.copyWith(color: color.onColor), ), Text( color.toHexNoAlpha().toUpperCase(), - style: Theme.of(context).textTheme.titleLarge?.copyWith(color: computeForeground(color)), + style: Theme.of(context).textTheme.titleLarge?.copyWith(color: color.onColor), ), Text( subtitle, - style: Theme.of(context).textTheme.bodySmall?.copyWith(color: computeForeground(color)), + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: color.onColor), ), ], ).padding(16), @@ -477,11 +485,11 @@ class _Swatch extends StatelessWidget { child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( headText, - style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: computeForeground(headColor)), + style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: headColor.onColor), ), const Expanded(child: SizedBox()), DefaultTextStyle( - style: Theme.of(context).textTheme.titleLarge!.copyWith(color: computeForeground(headColor)), + style: Theme.of(context).textTheme.titleLarge!.copyWith(color: headColor.onColor), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text('100%'), Text(headColor.toHexNoAlpha().toUpperCase())], @@ -500,11 +508,11 @@ class _Swatch extends StatelessWidget { children: [ Text( element['display'].toString(), - style: Theme.of(context).textTheme.titleMedium?.copyWith(color: computeForeground(color)), + style: Theme.of(context).textTheme.titleMedium?.copyWith(color: color.onColor), ), Text( color.toHexNoAlpha().toUpperCase(), - style: Theme.of(context).textTheme.titleMedium?.copyWith(color: computeForeground(color)), + style: Theme.of(context).textTheme.titleMedium?.copyWith(color: color.onColor), ), ], ).paddingOnly(left: 20, right: 20), diff --git a/example/lib/pages/theme/text.dart b/example/lib/pages/theme/text.dart index 6e25809..cab4664 100644 --- a/example/lib/pages/theme/text.dart +++ b/example/lib/pages/theme/text.dart @@ -1,81 +1,79 @@ import 'package:flutter/material.dart'; import 'package:zds_flutter/zds_flutter.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; class TextDemo extends StatelessWidget { const TextDemo({Key? key}) : super(key: key); -//?TODO: Integrate and use Zeta text themes @override Widget build(BuildContext context) { final display = [ { - 'header': 'Display Large', + 'header': 'H1 / displayLarge', 'textStyle': Theme.of(context).textTheme.displayLarge, }, { - 'header': 'Display Medium', + 'header': 'H2 / displayMedium', 'textStyle': Theme.of(context).textTheme.displayMedium, }, { - 'header': 'Display Small', + 'header': 'H3 / displaySmall', 'textStyle': Theme.of(context).textTheme.displaySmall, }, ]; final headline = [ { - 'header': 'Headline Large', + 'header': 'H3 / headlineLarge', 'textStyle': Theme.of(context).textTheme.headlineLarge, }, { - 'header': 'Headline Medium', + 'header': 'H4 / headlineMedium', 'textStyle': Theme.of(context).textTheme.headlineMedium, }, { - 'header': 'Headline Small', + 'header': 'H5 / headlineSmall', 'textStyle': Theme.of(context).textTheme.headlineSmall, }, ]; final body = [ { - 'header': 'Body Large', + 'header': 'Body 1 / bodyLarge', 'textStyle': Theme.of(context).textTheme.bodyLarge, }, { - 'header': 'Body Medium', + 'header': 'Body 2 / bodyMedium', 'textStyle': Theme.of(context).textTheme.bodyMedium, }, { - 'header': 'Body Small', + 'header': 'Body 3 / bodySmall', 'textStyle': Theme.of(context).textTheme.bodySmall, }, ]; final title = [ { - 'header': 'Title Large', + 'header': 'titleLarge', 'textStyle': Theme.of(context).textTheme.titleLarge, }, { - 'header': 'Title Medium', + 'header': 'Subtitle 1 / titleMedium', 'textStyle': Theme.of(context).textTheme.titleMedium, }, { - 'header': 'Title Small', + 'header': 'Subtiitle 2 / titleSmall', 'textStyle': Theme.of(context).textTheme.titleSmall, }, ]; final label = [ { - 'header': 'Label Large', + 'header': 'labelLarge', 'textStyle': Theme.of(context).textTheme.labelLarge, }, { - 'header': 'Label Medium', + 'header': 'labelMedium', 'textStyle': Theme.of(context).textTheme.labelMedium, }, { - 'header': 'Label Small', + 'header': 'labelSmall', 'textStyle': Theme.of(context).textTheme.labelSmall, }, ]; @@ -116,8 +114,8 @@ class _FontGroup extends StatelessWidget { children: [ Text(e['header'].toString(), style: style), Text( - 'Font: ${style.fontFamily?.split('/').last}\nSize: ${style.fontSize?.toInt()}\nLine height: ${(style.height ?? 1 * style.fontSize!).toInt()}', - style: TextStyle(color: ZetaColors.of(context).cool.shade70), + 'Font: ${style.fontFamily}\nSize: ${style.fontSize?.toInt()}\nLine height: ${((style.height ?? 1) * style.fontSize!).toInt()}', + style: TextStyle(color: Zeta.of(context).colors.textSubtle), ), const _Spacer(), ], @@ -125,7 +123,6 @@ class _FontGroup extends StatelessWidget { }) .toList() .divide(const _Spacer()), - const _Spacer(), const Divider(), const _Spacer(), ], diff --git a/example/lib/pages/utils/color_utils.dart b/example/lib/pages/utils/color_utils.dart index c761a05..0b822bc 100644 --- a/example/lib/pages/utils/color_utils.dart +++ b/example/lib/pages/utils/color_utils.dart @@ -46,7 +46,7 @@ class _ColorUtilsDemoState extends State { child: Center( child: Text( '#${color.toString().split('0xff').last.replaceAll(')', '').toUpperCase()}', - style: Theme.of(context).textTheme.displayMedium!.copyWith(color: ZdsColors.white), + style: Theme.of(context).textTheme.displayMedium?.copyWith(color: color.onColor), ), ), ), diff --git a/example/lib/pages/utils/theme_color_switch.dart b/example/lib/pages/utils/theme_color_switch.dart new file mode 100644 index 0000000..2490ac3 --- /dev/null +++ b/example/lib/pages/utils/theme_color_switch.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +class ZetaThemeColorSwitch extends StatelessWidget { + ZetaThemeColorSwitch({super.key}); + + late final _themes = { + "default": ZetaThemeData(), + "teal": ZetaThemeData( + identifier: 'teal', + primary: ZetaColorBase.teal, + ), + "yellow": ZetaThemeData( + identifier: 'yellow', + primary: ZetaColorBase.yellow, + ), + "red": ZetaThemeData( + identifier: 'red', + primary: ZetaColorBase.red, + ), + "purple": ZetaThemeData( + identifier: 'purple', + primary: ZetaColorBase.purple, + ), + }; + + @override + Widget build(BuildContext context) { + var zeta = Zeta.of(context); + + ZetaColors primary(ZetaThemeData data) { + if (zeta.brightness == Brightness.light) { + return data.colorsLight; + } else { + return data.colorsDark; + } + } + + return DropdownButtonHideUnderline( + child: DropdownButton( + value: zeta.themeData.identifier, + elevation: 0, + isDense: true, + alignment: Alignment.center, + icon: SizedBox(width: 8), + dropdownColor: zeta.colors.borderDisabled, + items: _themes.entries.map((e) { + var zetaColors = primary(_themes[e.key]!).apply(contrast: zeta.contrast); + var color = zetaColors.primary; + return DropdownMenuItem( + value: e.value.identifier, + alignment: Alignment.center, + child: CircleAvatar( + backgroundColor: color.surface, + foregroundColor: color, + child: Icon(Icons.color_lens, color: color), + ), + ); + }).toList(), + onChanged: (value) { + final theme = _themes[value]; + if (theme != null) { + ZetaProvider.of(context).updateThemeData(theme); + } + }, + ), + ); + } +} diff --git a/example/lib/pages/utils/theme_constrast_switch.dart b/example/lib/pages/utils/theme_constrast_switch.dart new file mode 100644 index 0000000..9d36c28 --- /dev/null +++ b/example/lib/pages/utils/theme_constrast_switch.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +class ZetaThemeContrastSwitch extends StatelessWidget { + ZetaThemeContrastSwitch({super.key}); + + late final _themes = [ + ZetaContrast.aa, + ZetaContrast.aaa, + ]; + + @override + Widget build(BuildContext context) { + var zeta = Zeta.of(context); + + ZetaColors zetaColors(ZetaContrast contrast) { + if (zeta.brightness == Brightness.light) { + return zeta.themeData.apply(contrast: contrast).colorsLight; + } else { + return zeta.themeData.apply(contrast: contrast).colorsDark; + } + } + + return DropdownButtonHideUnderline( + child: DropdownButton( + value: zeta.contrast, + elevation: 0, + isDense: true, + alignment: Alignment.center, + icon: SizedBox(width: 8), + dropdownColor: zeta.colors.borderDisabled, + items: _themes.map((e) { + final colors = zetaColors(e); + return DropdownMenuItem( + value: e, + alignment: Alignment.center, + child: CircleAvatar( + backgroundColor: colors.primary.surface, + foregroundColor: colors.primary, + child: ZetaText.bodyMedium( + e == ZetaContrast.aa ? 'AA' : 'AAA', + textColor: colors.primary, + fontWeight: FontWeight.w700, + ), + ), + ); + }).toList(), + onChanged: (value) { + if (value != null) { + ZetaProvider.of(context).updateContrast(value); + } + }, + ), + ); + } +} diff --git a/example/lib/pages/utils/theme_mode_switch.dart b/example/lib/pages/utils/theme_mode_switch.dart new file mode 100644 index 0000000..3531827 --- /dev/null +++ b/example/lib/pages/utils/theme_mode_switch.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +class ZetaThemeModeSwitch extends StatelessWidget { + ZetaThemeModeSwitch({super.key}); + + late final _themes = [ + ThemeMode.system, + ThemeMode.light, + ThemeMode.dark, + ]; + + @override + Widget build(BuildContext context) { + var zeta = Zeta.of(context); + + ZetaColors zetaColors(ThemeMode mode) { + if ((mode == ThemeMode.system && MediaQuery.of(context).platformBrightness == Brightness.light) || + mode == ThemeMode.light) { + return zeta.themeData.colorsLight; + } else { + return zeta.themeData.colorsDark; + } + } + + return DropdownButtonHideUnderline( + child: DropdownButton( + value: zeta.themeMode, + elevation: 0, + isDense: true, + alignment: Alignment.center, + icon: SizedBox(width: 8), + dropdownColor: zeta.colors.borderDisabled, + items: _themes.map((e) { + final colors = zetaColors(e).apply(contrast: zeta.contrast); + return DropdownMenuItem( + value: e, + alignment: Alignment.center, + child: CircleAvatar( + backgroundColor: colors.primary.surface, + foregroundColor: colors.primary, + child: Icon( + e == ThemeMode.system + ? Icons.system_security_update_good + : e == ThemeMode.light + ? Icons.light_mode + : Icons.dark_mode, + color: colors.primary), + ), + ); + }).toList(), + onChanged: (value) { + if (value != null) { + ZetaProvider.of(context).updateThemeMode(value); + } + }, + ), + ); + } +} diff --git a/example/lib/routes.dart b/example/lib/routes.dart index 18e128e..add75dc 100644 --- a/example/lib/routes.dart +++ b/example/lib/routes.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:zds_flutter_example/pages/theme/colors.dart'; +import 'package:zds_flutter_example/pages/theme/text.dart'; import 'home.dart'; -import 'pages/components/app_bar.dart'; import 'pages/assets/animations.dart'; import 'pages/assets/icons.dart'; import 'pages/assets/images.dart'; +import 'pages/components/app_bar.dart'; import 'pages/components/big_toggle_button.dart'; import 'pages/components/block_table.dart'; import 'pages/components/bottom_bar.dart'; @@ -13,44 +15,45 @@ import 'pages/components/bottom_tab_bar.dart'; import 'pages/components/bottom_tab_scaffold.dart'; import 'pages/components/button.dart'; import 'pages/components/calendar.dart'; -import 'pages/components/card.dart'; import 'pages/components/card_actions.dart'; +import 'pages/components/card.dart'; import 'pages/components/date_picker.dart'; import 'pages/components/day_picker_demo.dart'; +import 'pages/components/default_flutter.dart'; import 'pages/components/empty_list_view.dart'; import 'pages/components/empty_view.dart'; import 'pages/components/expandable.dart'; import 'pages/components/expansion_tile.dart'; import 'pages/components/file_picker.dart'; +import 'pages/components/html_view.dart'; import 'pages/components/icon_text_button.dart'; import 'pages/components/image_picker.dart'; import 'pages/components/index.dart'; import 'pages/components/infinite_list.dart'; import 'pages/components/information_bar.dart'; -import 'pages/components/list.dart'; import 'pages/components/list_tile.dart'; +import 'pages/components/list.dart'; +import 'pages/components/list_tile_wrapper.dart'; import 'pages/components/modal.dart'; import 'pages/components/navigation_menu.dart'; import 'pages/components/popover.dart'; import 'pages/components/profile.dart'; import 'pages/components/properties_list.dart'; +import 'pages/components/quill_editor_demo.dart'; import 'pages/components/radio_list.dart'; import 'pages/components/search.dart'; -import 'pages/components/shake_example.dart'; import 'pages/components/sheet_header.dart'; import 'pages/components/slidable_list_tile.dart'; import 'pages/components/split_navigator.dart'; import 'pages/components/stats_card.dart'; import 'pages/components/tab_bar.dart'; -import 'pages/components/tag.dart'; import 'pages/components/tag_list.dart'; +import 'pages/components/tag.dart'; import 'pages/components/text_field.dart'; -import 'pages/theme/colors.dart'; -import 'pages/theme/text.dart'; import 'pages/components/toast.dart'; import 'pages/components/toolbar.dart'; -import 'pages/utils/color_utils.dart'; import 'pages/components/vertical_nav.dart'; +import 'pages/utils/color_utils.dart'; final kRoutes = { 'Components': [ @@ -86,6 +89,10 @@ final kRoutes = { title: 'List tiles', child: ListTileDemo(), ), + const DemoRoute( + title: 'List tile wrapper', + child: ListTileWrapperDemo(), + ), const DemoRoute( title: 'Slidable list tiles', child: SlidableListTileDemo(), @@ -213,34 +220,43 @@ final kRoutes = { title: 'Days picker', child: DayPickerDemo(), ), + const DemoRoute( + title: 'Default Flutter', + child: DefaultFlutter(), + ), const DemoRoute(title: 'Infinite list', child: InfiniteListDemo()), const DemoRoute(title: 'Bottom Tab Bar Scaffold', child: BottomTabScaffoldDemo()), const DemoRoute(title: 'Sheet Headers', child: SheetHeaderDemo()), const DemoRoute(title: 'Vertical Navigation', child: VerticalNavDemo()), const DemoRoute(wrapper: false, title: 'Split Navigation', child: SplitNavigatorDemo()), + const DemoRoute(wrapper: false, title: 'Quill Editor', child: QuillEditorDemo()), + const DemoRoute(title: 'Html Preview', wrapper: false, child: HtmlPreview()), ], - 'Theme': [ - const DemoRoute(title: 'Text', child: TextDemo()), - const DemoRoute(title: 'Colors', child: ColorsDemo()), + 'Animations': [ + const DemoRoute(title: 'Colors generator', child: ColorUtilsDemo()), ], 'Assets': [ const DemoRoute(title: 'Animations', child: AnimationsDemo()), const DemoRoute(title: 'Images', child: ImagesDemo()), const DemoRoute(title: 'Icons', child: IconsDemo()) ], - 'Utils': [ - const DemoRoute(title: 'Colors', child: ColorUtilsDemo()), - const DemoRoute(title: 'Shake Animation', child: ShakeExample()), + 'Colors': [ + const DemoRoute(title: 'Colors', child: ColorsDemo()), + ], + 'Typography': [ + const DemoRoute(title: 'Typography', child: TextDemo()), ], }; final kFlattRoutes = kRoutes.keys.expand((key) => kRoutes[key]!).toList(); -const kHomeRoute = DemoRoute( - title: 'zds_flutter Demo', +final kHomeRoute = DemoRoute( + title: 'ZDS Flutter Demo', routeName: Navigator.defaultRouteName, wrapper: false, - child: HomePage(), + child: Builder(builder: (context) { + return HomePage(); + }), ); final kAllRoutes = { diff --git a/example/linux/flutter/generated_plugin_registrant.cc b/example/linux/flutter/generated_plugin_registrant.cc index 7299b5c..158f759 100644 --- a/example/linux/flutter/generated_plugin_registrant.cc +++ b/example/linux/flutter/generated_plugin_registrant.cc @@ -7,12 +7,16 @@ #include "generated_plugin_registrant.h" #include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) pasteboard_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); + pasteboard_plugin_register_with_registrar(pasteboard_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/example/linux/flutter/generated_plugins.cmake b/example/linux/flutter/generated_plugins.cmake index 786ff5c..93c755e 100644 --- a/example/linux/flutter/generated_plugins.cmake +++ b/example/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_linux + pasteboard url_launcher_linux ) diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index c93f1fa..3bd4a32 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,18 +5,30 @@ import FlutterMacOS import Foundation +import device_info_plus import file_selector_macos -import image_editor_common +import flutter_image_compress_macos +import package_info_plus +import pasteboard import path_provider_foundation +import shared_preferences_foundation import sqflite import url_launcher_macos import video_compress +import video_player_avfoundation +import wakelock_plus func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) - ImageEditorPlugin.register(with: registry.registrar(forPlugin: "ImageEditorPlugin")) + FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin")) + FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) + WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) } diff --git a/example/macos/Podfile b/example/macos/Podfile index b52666a..1f811a9 100644 --- a/example/macos/Podfile +++ b/example/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.15' +platform :osx, '14.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 3de18c4..ce348d6 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -1,16 +1,24 @@ PODS: + - device_info_plus (0.0.1): + - FlutterMacOS - file_selector_macos (0.0.1): - FlutterMacOS + - flutter_image_compress_macos (1.0.0): + - FlutterMacOS - FlutterMacOS (1.0.0) - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - image_editor_common (1.0.0): - - Flutter + - package_info_plus (0.0.1): + - FlutterMacOS + - pasteboard (0.0.1): - FlutterMacOS - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS - sqflite (0.0.2): - FlutterMacOS - FMDB (>= 2.7.5) @@ -18,46 +26,75 @@ PODS: - FlutterMacOS - video_compress (0.3.0): - FlutterMacOS + - video_player_avfoundation (0.0.1): + - Flutter + - FlutterMacOS + - wakelock_plus (0.0.1): + - FlutterMacOS DEPENDENCIES: + - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) + - flutter_image_compress_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_image_compress_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - - image_editor_common (from `Flutter/ephemeral/.symlinks/plugins/image_editor_common/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - video_compress (from `Flutter/ephemeral/.symlinks/plugins/video_compress/macos`) + - video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`) + - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) SPEC REPOS: trunk: - FMDB EXTERNAL SOURCES: + device_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos file_selector_macos: :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos + flutter_image_compress_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_image_compress_macos/macos FlutterMacOS: :path: Flutter/ephemeral - image_editor_common: - :path: Flutter/ephemeral/.symlinks/plugins/image_editor_common/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + pasteboard: + :path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos path_provider_foundation: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sqflite: :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos video_compress: :path: Flutter/ephemeral/.symlinks/plugins/video_compress/macos + video_player_avfoundation: + :path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin + wakelock_plus: + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos SPEC CHECKSUMS: + device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 + flutter_image_compress_macos: c26c3c13ea0f28ae6dea4e139b3292e7729f99f1 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - image_editor_common: 1b11f59fad8909bafcdaa0f31cc9373425b58600 + package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce + pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 video_compress: c896234f100791b5fef7f049afa38f6d2ef7b42f + video_player_avfoundation: e9e6f9cae7d7a6d9b43519b0aab382bca60fcfd1 + wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 -PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 +PODFILE CHECKSUM: 6acf97521436d16fc31cd5e1a02000905acdb3ae -COCOAPODS: 1.12.1 +COCOAPODS: 1.13.0 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 7fd9730..123a03d 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -195,7 +195,6 @@ 79A57FF7A45B475C2A8C6313 /* Pods-RunnerTests.release.xcconfig */, 080E8B4371495D57BEFB8951 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -546,6 +545,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + EXCLUDED_ARCHS = arm64; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -553,7 +553,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -570,12 +570,13 @@ CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + EXCLUDED_ARCHS = arm64; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 14.0; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -620,6 +621,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + EXCLUDED_ARCHS = arm64; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -633,7 +635,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -673,6 +675,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + EXCLUDED_ARCHS = arm64; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -680,7 +683,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -697,12 +700,13 @@ CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + EXCLUDED_ARCHS = arm64; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 14.0; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -718,12 +722,13 @@ CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + EXCLUDED_ARCHS = arm64; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 14.0; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bc02bb7..80ea669 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,24 +4,20 @@ publish_to: "none" version: 1.0.0+1 environment: - sdk: ">=3.0.1 <4.0.0" + sdk: ">=3.0.0 <4.0.0" + flutter: ">=3.7.0" dependencies: flutter: sdk: flutter - intl: ^0.18.0 lottie: ^2.1.0 + intl: ^0.18.0 table_calendar: ^3.0.9 + shared_preferences: ^2.2.2 zds_flutter: path: ../ -dev_dependencies: - flutter_lints: ^2.0.1 - flutter_test: - sdk: flutter - -dependency_overrides: - http: ^1.0.0 - flutter: uses-material-design: true + assets: + - assets/colors.json diff --git a/example/web/index.html b/example/web/index.html index 9299aa2..b33ba9b 100644 --- a/example/web/index.html +++ b/example/web/index.html @@ -10,9 +10,9 @@ it to work correctly. Fore more details: - * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base + * https://developer.mozilla.org/en-US/doc/Web/HTML/Element/base --> - + @@ -29,6 +29,8 @@ zds_flutter example + diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc index 043a96f..7d98a88 100644 --- a/example/windows/flutter/generated_plugin_registrant.cc +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -7,11 +7,14 @@ #include "generated_plugin_registrant.h" #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + PasteboardPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PasteboardPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index a95e267..722afbe 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows + pasteboard url_launcher_windows ) diff --git a/lib/assets/fonts/selection.json b/lib/assets/fonts/selection.json index 099d700..6fb58da 100644 --- a/lib/assets/fonts/selection.json +++ b/lib/assets/fonts/selection.json @@ -1,12 +1,43 @@ { "IcoMoonType": "selection", "icons": [ + { + "icon": { + "paths": [ + "M277.333 682.667c33.422 0 65.955 3.733 97.6 11.2s63.113 18.667 94.4 33.6v-420.267c-29.154-17.067-60.089-29.867-92.8-38.4s-65.778-12.8-99.2-12.8c-25.6 0-51.022 2.489-76.267 7.467s-49.6 12.445-73.067 22.4v422.4c24.889-8.533 49.6-14.933 74.133-19.2s49.6-6.4 75.2-6.4zM554.667 727.467c31.287-14.933 62.754-26.133 94.4-33.6s64.179-11.2 97.6-11.2c25.6 0 50.667 2.133 75.2 6.4s49.246 10.667 74.133 19.2v-422.4c-23.467-9.955-47.821-17.422-73.067-22.4s-50.667-7.467-76.267-7.467c-33.421 0-66.487 4.267-99.2 12.8s-63.646 21.333-92.8 38.4v420.267zM512 853.333c-34.133-27.021-71.113-48-110.933-62.933-39.822-14.933-81.067-22.4-123.733-22.4-29.867 0-59.2 3.913-88 11.733s-56.355 18.846-82.667 33.067c-14.933 7.821-29.333 7.467-43.2-1.067s-20.8-20.979-20.8-37.333v-514.133c0-7.822 1.955-15.289 5.867-22.4s9.778-12.445 17.6-16c32.711-17.067 66.845-29.867 102.4-38.4s71.822-12.8 108.8-12.8c41.245 0 81.6 5.333 121.067 16s77.333 26.667 113.6 48c36.267-21.333 74.133-37.333 113.6-48s79.821-16 121.067-16c36.979 0 73.246 4.267 108.8 12.8s69.687 21.333 102.4 38.4c7.821 3.555 13.687 8.889 17.6 16s5.867 14.578 5.867 22.4v514.133c0 16.354-6.933 28.8-20.8 37.333s-28.267 8.887-43.2 1.067c-26.313-14.221-53.867-25.246-82.667-33.067s-58.133-11.733-88-11.733c-42.667 0-83.913 7.467-123.733 22.4s-76.8 35.913-110.933 62.933z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "book_open" + ] + }, + "attrs": [ + {} + ], + "properties": { + "order": 4, + "id": 281, + "name": "book_open", + "prevSize": 32, + "code": 59817 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 0 + }, { "icon": { "paths": [ "M384 479.573v-159.573c0-58.88 47.787-106.667 106.667-106.667s106.667 47.787 106.667 106.667v159.573c51.627-34.56 85.333-93.013 85.333-159.573 0-106.24-85.76-192-192-192s-192 85.76-192 192c0 66.56 33.707 125.013 85.333 159.573zM803.84 677.12l-193.707-96.427c-7.253-2.987-14.933-4.693-23.040-4.693h-32.427v-256c0-35.413-28.587-64-64-64s-64 28.587-64 64v458.24c-153.6-32.427-151.040-32-156.587-32-13.227 0-25.173 5.547-33.707 14.080l-33.707 34.133 210.773 210.773c11.52 11.52 27.733 18.773 45.227 18.773h289.707c32 0 56.747-23.467 61.44-54.613l32-224.853c0.427-2.987 0.853-5.973 0.853-8.533 0-26.453-16.213-49.493-38.827-58.88z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "action" ], @@ -15,15 +46,15 @@ }, "attrs": [], "properties": { - "order": 570, - "id": 1, + "order": 1718, + "id": 0, "name": "action", "prevSize": 32, "code": 59821 }, "setIdx": 0, - "setId": 0, - "iconIdx": 0 + "setId": 2, + "iconIdx": 1 }, { "icon": { @@ -31,6 +62,8 @@ "M810.667 554.667h-256v256h-85.333v-256h-256v-85.333h256v-256h85.333v256h256v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "add" ], @@ -39,15 +72,15 @@ }, "attrs": [], "properties": { - "order": 571, - "id": 2, + "order": 1719, + "id": 1, "name": "add", "prevSize": 32, "code": 59651 }, "setIdx": 0, - "setId": 0, - "iconIdx": 1 + "setId": 2, + "iconIdx": 2 }, { "icon": { @@ -55,6 +88,8 @@ "M341.333 469.333h341.333v85.333h-341.333v-85.333zM857.6 512h81.067c0-117.759-95.573-213.332-213.333-213.332h-170.667v81.067h170.667c72.96 0 132.267 59.305 132.267 132.265zM166.4 512c0-72.96 59.307-132.265 132.267-132.265h170.667v-81.067h-170.667c-117.76 0-213.333 95.573-213.333 213.332s95.573 213.333 213.333 213.333h170.667v-81.067h-170.667c-72.96 0-132.267-59.307-132.267-132.267zM810.667 512h-85.333v128h-128v85.333h128v128h85.333v-128h128v-85.333h-128v-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "add link" ], @@ -63,15 +98,15 @@ }, "attrs": [], "properties": { - "order": 572, - "id": 3, + "order": 1720, + "id": 2, "name": "add-link", "prevSize": 32, "code": 59650 }, "setIdx": 0, - "setId": 0, - "iconIdx": 2 + "setId": 2, + "iconIdx": 3 }, { "icon": { @@ -79,6 +114,8 @@ "M938.667 221.013l-486.827 487.253-180.907-180.907 60.16-60.16 120.747 120.747 426.667-426.667 60.16 59.733zM512 853.333c-188.16 0-341.333-153.173-341.333-341.333s153.173-341.333 341.333-341.333c66.987 0 129.707 19.627 182.613 53.333l61.867-61.867c-71.723-49.996-157.052-76.801-244.48-76.8-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c73.813 0 143.36-18.773 203.947-52.053l-64-64c-42.667 19.627-90.027 30.72-139.947 30.72zM810.667 640h-128v85.333h128v128h85.333v-128h128v-85.333h-128v-128h-85.333v128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "add task" ], @@ -87,15 +124,15 @@ }, "attrs": [], "properties": { - "order": 573, - "id": 4, + "order": 1721, + "id": 3, "name": "add-task", "prevSize": 32, "code": 59724 }, "setIdx": 0, - "setId": 0, - "iconIdx": 3 + "setId": 2, + "iconIdx": 4 }, { "icon": { @@ -103,6 +140,8 @@ "M341.333 426.667h-128v-128h-85.333v128h-128v85.333h128v128h85.333v-128h128v-85.333zM768 469.333c70.827 0 127.573-57.173 127.573-128s-56.747-128-127.573-128c-13.653 0-26.88 2.133-38.827 5.973 24.32 34.56 38.4 76.373 38.4 122.027s-14.507 87.040-38.4 122.027c11.947 3.84 25.173 5.973 38.827 5.973zM554.667 469.333c70.827 0 127.573-57.173 127.573-128s-56.747-128-127.573-128c-70.827 0-128 57.173-128 128s57.173 128 128 128zM837.12 561.493c35.413 31.147 58.88 70.827 58.88 121.173v85.333h128v-85.333c0-65.707-101.12-106.24-186.88-121.173zM554.667 554.667c-85.333 0-256 42.667-256 128v85.333h512v-85.333c0-85.333-170.667-128-256-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "add user" ], @@ -111,15 +150,15 @@ }, "attrs": [], "properties": { - "order": 574, - "id": 5, + "order": 1722, + "id": 4, "name": "add-user", "prevSize": 32, "code": 59652 }, "setIdx": 0, - "setId": 0, - "iconIdx": 4 + "setId": 2, + "iconIdx": 5 }, { "icon": { @@ -127,6 +166,8 @@ "M512 960c-129.707 0-234.667-104.96-234.667-234.667v-448c0-94.293 76.373-170.667 170.667-170.667s170.667 76.373 170.667 170.667v362.667c0 58.88-47.787 106.667-106.667 106.667s-106.667-47.787-106.667-106.667v-320h85.333v323.84c0 23.467 42.667 23.467 42.667 0v-366.507c0-46.933-38.4-85.333-85.333-85.333s-85.333 38.4-85.333 85.333v448c0 82.347 66.987 149.333 149.333 149.333s149.333-66.987 149.333-149.333v-405.333h85.333v405.333c0 129.707-104.96 234.667-234.667 234.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "attachment" ], @@ -135,15 +176,15 @@ }, "attrs": [], "properties": { - "order": 575, - "id": 6, + "order": 1723, + "id": 5, "name": "attachment", "prevSize": 32, "code": 59653 }, "setIdx": 0, - "setId": 0, - "iconIdx": 5 + "setId": 2, + "iconIdx": 6 }, { "icon": { @@ -151,6 +192,8 @@ "M128 384v256h170.667l213.333 213.333v-682.667l-213.333 213.333h-170.667zM704 512c0-75.52-43.52-140.373-106.667-171.947v343.467c63.147-31.147 106.667-96 106.667-171.52zM597.333 137.813v87.893c123.307 36.693 213.333 151.040 213.333 286.293s-90.027 249.6-213.333 286.293v87.893c171.093-38.827 298.667-191.573 298.667-374.187s-127.573-335.36-298.667-374.187z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "audio" ], @@ -159,15 +202,15 @@ }, "attrs": [], "properties": { - "order": 576, - "id": 7, + "order": 1724, + "id": 6, "name": "audio", "prevSize": 32, "code": 59823 }, "setIdx": 0, - "setId": 0, - "iconIdx": 6 + "setId": 2, + "iconIdx": 7 }, { "icon": { @@ -175,6 +218,8 @@ "M597.333 85.333h-341.333c-46.933 0-85.333 38.4-85.333 85.333v682.667c0 46.933 38.4 85.333 85.333 85.333h512c46.933 0 85.333-38.4 85.333-85.333v-512l-256-256zM256 853.333v-682.667h298.667v213.333h213.333v469.333h-512zM682.667 469.333h-170.667v165.547c-15.36-10.24-33.707-16.213-53.333-16.213-52.907 0-96 43.093-96 96s43.093 96 96 96c52.907 0 96-43.093 96-96v-160h128v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "audio-file" ], @@ -183,15 +228,15 @@ }, "attrs": [], "properties": { - "order": 577, - "id": 8, + "order": 1725, + "id": 7, "name": "audio-file", "prevSize": 32, "code": 59654 }, "setIdx": 0, - "setId": 0, - "iconIdx": 7 + "setId": 2, + "iconIdx": 8 }, { "icon": { @@ -199,23 +244,31 @@ "M517.419 166.699c-20.821-64.171-83.755-97.067-139.648-74.027-31.445 12.331-54.827 39.467-66.56 74.027h-152.747l-0.043 0c-20.617 0.247-39.067 9.505-51.669 24.106-13.739 15.403-21.419 36.352-21.419 58.155v575.744l0-0.038c-0.002 0.251-0.003 0.501-0.003 0.752 0 22.019 8.113 42.144 21.422 57.441 13.739 15.403 32.299 24.064 51.712 24.064h231.936c-9.088-25.984-14.805-53.589-16.64-82.219h-215.296v-575.744h73.088v82.219h365.568v-82.219h73.088v247.808l-0.577 0.018c4.009-0.154 8.038-0.231 12.085-0.231 21.812 0 43.097 2.253 61.623 6.187v-253.781c0-21.845-7.723-42.752-21.419-58.155-13.739-15.445-32.299-24.107-51.712-24.107h-152.789zM472.917 577.963h-241.365v82.219h177.707l0.81-1.633c16.361-30.171 37.59-57.319 62.849-80.586zM440.192 178.731c6.827 7.765 10.667 18.176 10.667 29.099s-3.84 21.376-10.667 29.056l-0.038 0.045c-6.258 7.266-15.484 11.903-25.818 12.030-9.685 0-19.029-4.352-25.856-12.075s-10.667-18.133-10.667-29.056c0-10.923 3.84-21.376 10.667-29.099l0.037-0.044c6.265-7.251 15.491-11.873 25.819-11.988l0.020 0c10.308 0.115 19.533 4.737 25.836 12.032zM231.552 413.44h365.568v82.261h-365.568v-82.261z", "M611.627 618.325c12.617 0.786 23.286 8.402 28.414 19.167l0.087 0.204 91.819 196.693 51.413-82.261c6.057-9.569 16.585-15.829 28.575-15.829 0.004 0 0.008 0 0.012 0l101.205-0c18.616 0 33.707 15.091 33.707 33.707s-15.091 33.707-33.707 33.707v0h-82.517l-74.411 119.083c-6.053 9.587-16.592 15.861-28.595 15.861-13.438 0-25.040-7.864-30.454-19.241l-0.087-0.204-91.819-196.693-51.413 82.261c-6.057 9.569-16.585 15.829-28.575 15.829-0.004 0-0.008-0-0.012-0l-101.205 0c-18.616 0-33.707-15.091-33.707-33.707s15.091-33.707 33.707-33.707h82.517l74.411-119.083c6.055-9.58 16.589-15.849 28.587-15.849 0.72 0 1.435 0.023 2.144 0.067l-0.097-0.005z" ], - "attrs": [], + "attrs": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "audit-activity" ], "grid": 16 }, - "attrs": [], + "attrs": [ + {}, + {} + ], "properties": { - "order": 578, - "id": 9, + "order": 1726, + "id": 8, "name": "audit-activity", "prevSize": 32, "code": 59648 }, "setIdx": 0, - "setId": 0, - "iconIdx": 8 + "setId": 2, + "iconIdx": 9 }, { "icon": { @@ -223,6 +276,8 @@ "M853.333 469.333h-519.253l238.507-238.507-60.587-60.16-341.333 341.333 341.333 341.333 60.16-60.16-238.080-238.507h519.253v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "back" ], @@ -231,15 +286,15 @@ }, "attrs": [], "properties": { - "order": 579, - "id": 10, + "order": 1727, + "id": 9, "name": "back", "prevSize": 32, "code": 59655 }, "setIdx": 0, - "setId": 0, - "iconIdx": 9 + "setId": 2, + "iconIdx": 10 }, { "icon": { @@ -247,6 +302,8 @@ "M853.333 128h-682.667v426.667c0 94.293 76.373 170.667 170.667 170.667h256c94.293 0 170.667-76.373 170.667-170.667v-128h85.333c47.36 0 85.333-38.4 85.333-85.333v-128c0-47.36-37.973-85.333-85.333-85.333zM853.333 341.333h-85.333v-128h85.333v128zM170.667 810.667h682.667v85.333h-682.667v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "break" ], @@ -255,15 +312,15 @@ }, "attrs": [], "properties": { - "order": 580, - "id": 11, - "name": "break-", + "order": 1728, + "id": 10, + "name": "break-filled", "prevSize": 32, "code": 59824 }, "setIdx": 0, - "setId": 0, - "iconIdx": 10 + "setId": 2, + "iconIdx": 11 }, { "icon": { @@ -271,6 +328,8 @@ "M768 469.333v85.333h170.667v-85.333h-170.667zM682.667 751.36c40.96 30.293 94.293 70.4 136.533 101.973 17.067-22.613 34.133-45.653 51.2-68.267-42.24-31.573-95.573-71.68-136.533-102.4-17.067 23.040-34.133 46.080-51.2 68.693zM870.4 238.933c-17.067-22.613-34.133-45.653-51.2-68.267-42.24 31.573-95.573 71.68-136.533 102.4 17.067 22.613 34.133 45.653 51.2 68.267 40.96-30.72 94.293-70.4 136.533-102.4zM170.667 384c-46.933 0-85.333 38.4-85.333 85.333v85.333c0 46.933 38.4 85.333 85.333 85.333h42.667v170.667h85.333v-170.667h42.667l213.333 128v-512l-213.333 128h-170.667zM661.333 512c0-56.747-24.747-107.947-64-142.933v285.44c39.253-34.56 64-85.76 64-142.507z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "broadcast" ], @@ -279,15 +338,15 @@ }, "attrs": [], "properties": { - "order": 581, - "id": 12, + "order": 1729, + "id": 11, "name": "broadcast", "prevSize": 32, "code": 59825 }, "setIdx": 0, - "setId": 0, - "iconIdx": 11 + "setId": 2, + "iconIdx": 12 }, { "icon": { @@ -295,6 +354,8 @@ "M512 298.667v-170.667h-426.667v768h853.333v-597.333h-426.667zM256 810.667h-85.333v-85.333h85.333v85.333zM256 640h-85.333v-85.333h85.333v85.333zM256 469.333h-85.333v-85.333h85.333v85.333zM256 298.667h-85.333v-85.333h85.333v85.333zM426.667 810.667h-85.333v-85.333h85.333v85.333zM426.667 640h-85.333v-85.333h85.333v85.333zM426.667 469.333h-85.333v-85.333h85.333v85.333zM426.667 298.667h-85.333v-85.333h85.333v85.333zM853.333 810.667h-341.333v-85.333h85.333v-85.333h-85.333v-85.333h85.333v-85.333h-85.333v-85.333h341.333v426.667zM768 469.333h-85.333v85.333h85.333v-85.333zM768 640h-85.333v85.333h85.333v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "building" ], @@ -303,15 +364,15 @@ }, "attrs": [], "properties": { - "order": 582, - "id": 13, + "order": 1730, + "id": 12, "name": "building", "prevSize": 32, "code": 59826 }, "setIdx": 0, - "setId": 0, - "iconIdx": 12 + "setId": 2, + "iconIdx": 13 }, { "icon": { @@ -319,6 +380,8 @@ "M832 170.667h-42.667v-85.333h-85.333v85.333h-341.333v-85.333h-85.333v85.333h-42.667c-47.128 0-85.333 38.205-85.333 85.333v0 597.333c0 46.933 38.4 85.333 85.333 85.333h597.333c47.128 0 85.333-38.205 85.333-85.333v0-597.333c0-47.128-38.205-85.333-85.333-85.333v0zM832 853.333h-597.333v-469.333h597.333v469.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar" ], @@ -327,15 +390,15 @@ }, "attrs": [], "properties": { - "order": 583, - "id": 14, + "order": 1731, + "id": 13, "name": "calendar", "prevSize": 32, "code": 59759 }, "setIdx": 0, - "setId": 0, - "iconIdx": 13 + "setId": 2, + "iconIdx": 14 }, { "icon": { @@ -343,6 +406,8 @@ "M384 469.333h-85.333v85.333h85.333v-85.333zM554.667 469.333h-85.333v85.333h85.333v-85.333zM725.333 469.333h-85.333v85.333h85.333v-85.333zM810.667 170.667h-42.667v-85.333h-85.333v85.333h-341.333v-85.333h-85.333v85.333h-42.667c-47.36 0-84.907 38.4-84.907 85.333l-0.427 597.333c0 46.933 37.973 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333zM810.667 853.333h-597.333v-469.333h597.333v469.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-3-day" ], @@ -351,15 +416,15 @@ }, "attrs": [], "properties": { - "order": 584, - "id": 15, + "order": 1732, + "id": 14, "name": "calendar-3-day", "prevSize": 32, "code": 59827 }, "setIdx": 0, - "setId": 0, - "iconIdx": 14 + "setId": 2, + "iconIdx": 15 }, { "icon": { @@ -368,6 +433,8 @@ "M725.333 512c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333c117.76 0 213.333-95.573 213.333-213.333s-95.573-213.333-213.333-213.333zM682.667 832l-106.667-106.667 30.080-30.080 76.587 76.373 161.92-161.92 30.080 30.293-192 192z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-available" ], @@ -376,15 +443,15 @@ }, "attrs": [], "properties": { - "order": 585, - "id": 16, + "order": 1733, + "id": 15, "name": "calendar-available", "prevSize": 32, "code": 59828 }, "setIdx": 0, - "setId": 0, - "iconIdx": 15 + "setId": 2, + "iconIdx": 16 }, { "icon": { @@ -392,6 +459,8 @@ "M384 469.333h-85.333v85.333h85.333v-85.333zM810.667 170.667h-42.667v-85.333h-85.333v85.333h-341.333v-85.333h-85.333v85.333h-42.667c-47.36 0-84.907 38.4-84.907 85.333l-0.427 597.333c0 46.933 37.973 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333zM810.667 853.333h-597.333v-469.333h597.333v469.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-day" ], @@ -400,15 +469,15 @@ }, "attrs": [], "properties": { - "order": 586, - "id": 17, + "order": 1734, + "id": 16, "name": "calendar-day", "prevSize": 32, "code": 59829 }, "setIdx": 0, - "setId": 0, - "iconIdx": 16 + "setId": 2, + "iconIdx": 17 }, { "icon": { @@ -417,6 +486,8 @@ "M597.333 824.9v71.1h71.1l209.702-209.702-71.1-71.1-209.702 209.702zM933.12 631.313c7.394-7.394 7.394-19.341 0-26.735l-44.365-44.365c-7.394-7.394-19.341-7.394-26.735 0l-34.697 34.697 71.1 71.1 34.697-34.697z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-edit" ], @@ -425,15 +496,15 @@ }, "attrs": [], "properties": { - "order": 587, - "id": 18, + "order": 1735, + "id": 17, "name": "calendar-edit", "prevSize": 32, "code": 59830 }, "setIdx": 0, - "setId": 0, - "iconIdx": 17 + "setId": 2, + "iconIdx": 18 }, { "icon": { @@ -443,6 +514,8 @@ "M298.667 725.333v-85.333h298.667v85.333h-298.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-month" ], @@ -451,15 +524,15 @@ }, "attrs": [], "properties": { - "order": 588, - "id": 19, + "order": 1736, + "id": 18, "name": "calendar-month", "prevSize": 32, "code": 59831 }, "setIdx": 0, - "setId": 0, - "iconIdx": 18 + "setId": 2, + "iconIdx": 19 }, { "icon": { @@ -468,6 +541,8 @@ "M1024.004 731.26l-64 64.004c-85.299-85.299-256.034-89.161-341.333-3.861-30.298 30.298-55.317 85.559-64 124.352h80.282c7.334-24.704 21.035-48.055 40.525-67.546 63.876-63.876 167.701-63.876 231.582 0l-57.899 57.894 174.844 0.004v-174.848z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-rollover" ], @@ -476,15 +551,15 @@ }, "attrs": [], "properties": { - "order": 589, - "id": 20, + "order": 1737, + "id": 19, "name": "calendar-rollover", "prevSize": 32, "code": 59832 }, "setIdx": 0, - "setId": 0, - "iconIdx": 19 + "setId": 2, + "iconIdx": 20 }, { "icon": { @@ -492,6 +567,8 @@ "M810.667 85.333h-42.667v-85.333h-85.333v85.333h-341.333v-85.333h-85.333v85.333h-42.667c-47.128 0-85.333 38.205-85.333 85.333v0 597.333c0 46.933 38.4 85.333 85.333 85.333h597.333c47.128 0 85.333-38.205 85.333-85.333v0-597.333c0-47.128-38.205-85.333-85.333-85.333v0zM810.667 768h-597.333v-469.333h597.333v469.333zM298.667 384h213.333v213.333h-213.333v-213.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-today" ], @@ -500,15 +577,15 @@ }, "attrs": [], "properties": { - "order": 590, - "id": 21, + "order": 1738, + "id": 20, "name": "calendar-today", "prevSize": 32, "code": 59749 }, "setIdx": 0, - "setId": 0, - "iconIdx": 20 + "setId": 2, + "iconIdx": 21 }, { "icon": { @@ -517,6 +594,8 @@ "M619.968 682.351l91.802-91.802-91.802-91.802v75.507h-229.499v-75.507l-91.8 91.802 91.8 91.802v-75.507h229.499v75.507z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-trade" ], @@ -525,15 +604,15 @@ }, "attrs": [], "properties": { - "order": 591, - "id": 22, + "order": 1739, + "id": 21, "name": "calendar-trade", "prevSize": 32, "code": 59834 }, "setIdx": 0, - "setId": 0, - "iconIdx": 21 + "setId": 2, + "iconIdx": 22 }, { "icon": { @@ -542,6 +621,8 @@ "M725.333 512c-117.821 0-213.333 95.513-213.333 213.333s95.513 213.333 213.333 213.333v0c117.821 0 213.333-95.513 213.333-213.333s-95.513-213.333-213.333-213.333v0zM832 802.133l-29.867 29.867-76.8-76.8-76.8 76.8-29.867-29.867 76.8-76.8-76.8-76.8 29.867-29.867 76.8 76.8 76.8-76.8 29.867 29.867-76.8 76.8 76.8 76.8z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-unavailable" ], @@ -550,15 +631,15 @@ }, "attrs": [], "properties": { - "order": 592, - "id": 23, + "order": 1740, + "id": 22, "name": "calendar-unavailable", "prevSize": 32, "code": 59756 }, "setIdx": 0, - "setId": 0, - "iconIdx": 22 + "setId": 2, + "iconIdx": 23 }, { "icon": { @@ -567,6 +648,8 @@ "M298.667 554.667v-85.333h426.667v85.333h-426.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-week" ], @@ -575,15 +658,15 @@ }, "attrs": [], "properties": { - "order": 593, - "id": 24, + "order": 1741, + "id": 23, "name": "calendar-week", "prevSize": 32, "code": 59836 }, "setIdx": 0, - "setId": 0, - "iconIdx": 23 + "setId": 2, + "iconIdx": 24 }, { "icon": { @@ -597,6 +680,8 @@ "M640 725.333h85.333v85.333h-85.333v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "calendar-year" ], @@ -605,15 +690,15 @@ }, "attrs": [], "properties": { - "order": 594, - "id": 25, + "order": 1742, + "id": 24, "name": "calendar-year", "prevSize": 32, "code": 59837 }, "setIdx": 0, - "setId": 0, - "iconIdx": 24 + "setId": 2, + "iconIdx": 25 }, { "icon": { @@ -621,6 +706,8 @@ "M853.76 656.213c-52.48 0-103.253-8.533-150.613-23.893-14.933-5.12-31.573-1.28-43.093 10.24l-66.987 84.053c-120.747-57.6-233.813-166.4-293.973-291.413l83.2-70.827c11.52-11.947 14.933-28.587 10.24-43.52-15.787-47.36-23.893-98.133-23.893-150.613 0-23.040-19.2-42.24-42.24-42.24h-147.627c-23.040 0-50.773 10.24-50.773 42.24 0 396.373 329.813 725.76 725.76 725.76 30.293 0 42.24-26.88 42.24-50.347v-147.2c0-23.040-19.2-42.24-42.24-42.24z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "call" ], @@ -629,15 +716,15 @@ }, "attrs": [], "properties": { - "order": 595, - "id": 26, + "order": 1743, + "id": 25, "name": "call", "prevSize": 32, "code": 59839 }, "setIdx": 0, - "setId": 0, - "iconIdx": 25 + "setId": 2, + "iconIdx": 26 }, { "icon": { @@ -646,6 +733,8 @@ "M384 85.333l-78.080 85.333h-135.253c-46.933 0-85.333 38.4-85.333 85.333v512c0 46.933 38.4 85.333 85.333 85.333h682.667c46.933 0 85.333-38.4 85.333-85.333v-512c0-46.933-38.4-85.333-85.333-85.333h-135.253l-78.080-85.333h-256zM512 725.333c-117.76 0-213.333-95.573-213.333-213.333s95.573-213.333 213.333-213.333c117.76 0 213.333 95.573 213.333 213.333s-95.573 213.333-213.333 213.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "camera" ], @@ -654,15 +743,15 @@ }, "attrs": [], "properties": { - "order": 596, - "id": 27, + "order": 1744, + "id": 26, "name": "camera", "prevSize": 32, "code": 59741 }, "setIdx": 0, - "setId": 0, - "iconIdx": 26 + "setId": 2, + "iconIdx": 27 }, { "icon": { @@ -672,6 +761,8 @@ "M467.2 936.96c-201.387-20.053-361.813-180.48-381.867-381.867h-85.333c28.16 340.053 363.093 536.747 658.347 447.147l-191.147-191.147v125.867z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "camera-switch" ], @@ -680,15 +771,15 @@ }, "attrs": [], "properties": { - "order": 597, - "id": 28, + "order": 1745, + "id": 27, "name": "camera-switch", "prevSize": 32, "code": 59740 }, "setIdx": 0, - "setId": 0, - "iconIdx": 27 + "setId": 2, + "iconIdx": 28 }, { "icon": { @@ -697,6 +788,8 @@ ], "width": 1056, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "category" ], @@ -705,15 +798,15 @@ }, "attrs": [], "properties": { - "order": 598, - "id": 29, + "order": 1746, + "id": 28, "name": "category", "prevSize": 32, "code": 59656 }, "setIdx": 0, - "setId": 0, - "iconIdx": 28 + "setId": 2, + "iconIdx": 29 }, { "icon": { @@ -721,6 +814,8 @@ "M853.333 298.667h-213.333v-128c0-46.933-38.4-85.333-85.333-85.333h-85.333c-46.933 0-85.333 38.4-85.333 85.333v128h-213.333c-46.933 0-85.333 38.4-85.333 85.333v469.333c0 46.933 38.4 85.333 85.333 85.333h682.667c46.933 0 85.333-38.4 85.333-85.333v-469.333c0-46.933-38.4-85.333-85.333-85.333zM384 512c35.413 0 64 28.587 64 64s-28.587 64-64 64c-35.413 0-64-28.587-64-64s28.587-64 64-64zM512 768h-256v-32c0-42.667 85.333-64 128-64s128 21.333 128 64v32zM554.667 384h-85.333v-213.333h85.333v213.333zM768 704h-170.667v-64h170.667v64zM768 576h-170.667v-64h170.667v64z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "certified" ], @@ -729,15 +824,15 @@ }, "attrs": [], "properties": { - "order": 599, - "id": 30, + "order": 1747, + "id": 29, "name": "certified", "prevSize": 32, "code": 59840 }, "setIdx": 0, - "setId": 0, - "iconIdx": 29 + "setId": 2, + "iconIdx": 30 }, { "icon": { @@ -745,6 +840,8 @@ "M301.767 683.938l109.95-248.324c5.318-12.011 14.648-21.642 26.282-27.132l240.567-113.497c27.75-13.092 56.35 16.413 43.665 45.075l-109.948 248.326c-5.321 12.011-14.647 21.641-26.283 27.132l-240.568 113.498c-27.767 13.090-56.35-16.414-43.666-45.077zM549.632 550.848c20.783-21.453 20.783-56.243 0-77.696s-54.481-21.453-75.264 0c-20.783 21.453-20.783 56.243 0 77.696s54.481 21.453 75.264 0zM98.667 512c0-235.647 185.050-426.667 413.333-426.667s413.333 191.020 413.333 426.667c0 235.648-185.050 426.667-413.333 426.667s-413.333-191.019-413.333-426.667zM845.333 512c0-189.729-149.534-344.086-333.333-344.086s-333.333 154.357-333.333 344.086c0 189.73 149.533 344.085 333.333 344.085s333.333-154.355 333.333-344.085z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "channel" ], @@ -753,15 +850,15 @@ }, "attrs": [], "properties": { - "order": 600, - "id": 31, + "order": 1748, + "id": 30, "name": "channel", "prevSize": 32, "code": 59657 }, "setIdx": 0, - "setId": 0, - "iconIdx": 30 + "setId": 2, + "iconIdx": 31 }, { "icon": { @@ -769,6 +866,8 @@ "M640 170.667v298.667h-419.413l-49.92 49.92v-348.587h469.333zM682.667 85.333h-554.667c-23.467 0-42.667 19.2-42.667 42.667v597.333l170.667-170.667h426.667c23.467 0 42.667-19.2 42.667-42.667v-384c0-23.467-19.2-42.667-42.667-42.667zM896 256h-85.333v384h-554.667v85.333c0 23.467 19.2 42.667 42.667 42.667h469.333l170.667 170.667v-640c0-23.467-19.2-42.667-42.667-42.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chat" ], @@ -777,15 +876,15 @@ }, "attrs": [], "properties": { - "order": 601, - "id": 32, + "order": 1749, + "id": 31, "name": "chat", "prevSize": 32, "code": 59847 }, "setIdx": 0, - "setId": 0, - "iconIdx": 31 + "setId": 2, + "iconIdx": 32 }, { "icon": { @@ -794,6 +893,8 @@ "M616.017 400.842c22.366 0 40.422-18.055 40.422-40.421s-18.057-40.421-40.422-40.421c-22.366 0-40.422 18.055-40.422 40.421s18.057 40.421 40.422 40.421zM427.383 400.842c22.37 0 40.422-18.055 40.422-40.421s-18.052-40.421-40.422-40.421c-22.365 0-40.419 18.055-40.419 40.421s18.055 40.421 40.419 40.421zM521.702 576c62.784 0 116.143-39.343 137.698-94.315h-275.401c21.558 54.972 74.914 94.315 137.702 94.315z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chat-bot" ], @@ -802,15 +903,15 @@ }, "attrs": [], "properties": { - "order": 602, - "id": 33, + "order": 1750, + "id": 32, "name": "chat-bot", "prevSize": 32, "code": 59841 }, "setIdx": 0, - "setId": 0, - "iconIdx": 32 + "setId": 2, + "iconIdx": 33 }, { "icon": { @@ -818,6 +919,8 @@ "M785.067 170.667h-546.133c-37.547 0-68.267 30.72-68.267 68.267v614.4l136.533-136.533h477.867c37.547 0 68.267-30.72 68.267-68.267v-409.6c0-37.547-30.72-68.267-68.267-68.267zM785.067 648.533h-477.867l-68.267 68.267v-477.867h546.133v409.6z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chat-message" ], @@ -826,15 +929,15 @@ }, "attrs": [], "properties": { - "order": 603, - "id": 34, + "order": 1751, + "id": 33, "name": "chat-message", "prevSize": 32, "code": 59845 }, "setIdx": 0, - "setId": 0, - "iconIdx": 33 + "setId": 2, + "iconIdx": 34 }, { "icon": { @@ -842,6 +945,8 @@ "M455.1 644.023l58.871-59.78 21.321 21.619 344.461-349.862 58.914 59.736-403.375 409.597-80.192-81.31zM279.291 605.862l344.462-349.862 58.914 59.736-403.376 409.597-195.083-198.4 58.914-59.733 136.169 138.662z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chat-message-read" ], @@ -850,15 +955,44 @@ }, "attrs": [], "properties": { - "order": 604, - "id": 35, + "order": 1752, + "id": 34, "name": "chat-message-read", "prevSize": 32, "code": 59842 }, "setIdx": 0, - "setId": 0, - "iconIdx": 34 + "setId": 2, + "iconIdx": 35 + }, + { + "icon": { + "paths": [ + "M742.402 468.76c66.248-17.052 115.196-77.19 115.196-148.76 0-84.834-68.766-153.602-153.6-153.602-71.574 0-131.714 48.954-148.764 115.204h-365.796c-33.79 0-61.438 27.648-61.438 61.438v552.962l122.878-122.882h430.082c33.794 0 61.442-27.648 61.442-61.44v-242.92zM680.96 471.884v239.798h-430.082l-61.438 61.438v-430.080h362.672c9.986 66.388 62.46 118.86 128.848 128.844z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "chat-message-unread" + ], + "grid": 16 + }, + "attrs": [ + {} + ], + "properties": { + "order": 1753, + "id": 35, + "name": "chat-message-unread", + "prevSize": 32, + "code": 59744 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 36 }, { "icon": { @@ -867,6 +1001,8 @@ "M238.933 170.667h546.133c37.547 0 68.267 30.72 68.267 68.267v62.758c-13.935-1.993-28.181-3.025-42.667-3.025-8.623 0-17.161 0.366-25.6 1.082v-60.815h-546.133v477.867l68.267-68.267h209.173c4.117 23.842 11.063 46.716 20.48 68.267h-229.653l-136.533 136.533v-614.4c0-37.547 30.72-68.267 68.267-68.267z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chat-search" ], @@ -875,15 +1011,15 @@ }, "attrs": [], "properties": { - "order": 606, - "id": 37, + "order": 1754, + "id": 36, "name": "chat-search", "prevSize": 32, "code": 59846 }, "setIdx": 0, - "setId": 0, - "iconIdx": 35 + "setId": 2, + "iconIdx": 37 }, { "icon": { @@ -891,6 +1027,8 @@ "M785.067 170.667h-546.133c-37.547 0-68.267 30.72-68.267 68.267v614.4l136.533-136.533h477.867c37.547 0 68.267-30.72 68.267-68.267v-409.6c0-37.547-30.72-68.267-68.267-68.267zM785.067 648.533h-477.867l-68.267 68.267v-477.867h546.133v409.6z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chat-unread active" ], @@ -899,15 +1037,15 @@ }, "attrs": [], "properties": { - "order": 607, - "id": 38, + "order": 1755, + "id": 37, "name": "chat-unread-active", "prevSize": 32, "code": 59658 }, "setIdx": 0, - "setId": 0, - "iconIdx": 36 + "setId": 2, + "iconIdx": 38 }, { "icon": { @@ -915,6 +1053,8 @@ "M384.007 689.92l-177.92-177.92-60.587 60.16 238.507 238.507 512.002-512-60.16-60.16-451.842 451.413z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "check" ], @@ -923,15 +1063,15 @@ }, "attrs": [], "properties": { - "order": 608, - "id": 39, + "order": 1756, + "id": 38, "name": "check", "prevSize": 32, "code": 59659 }, "setIdx": 0, - "setId": 0, - "iconIdx": 37 + "setId": 2, + "iconIdx": 39 }, { "icon": { @@ -939,6 +1079,8 @@ "M512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM426.667 725.333l-213.333-213.333 60.16-60.16 153.173 152.747 323.84-323.84 60.16 60.587-384 384z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "check circle" ], @@ -947,15 +1089,15 @@ }, "attrs": [], "properties": { - "order": 609, - "id": 40, + "order": 1757, + "id": 39, "name": "check-circle", "prevSize": 32, "code": 59660 }, "setIdx": 0, - "setId": 0, - "iconIdx": 38 + "setId": 2, + "iconIdx": 40 }, { "icon": { @@ -963,6 +1105,8 @@ "M303.577 353.921l-60.16 60.16 256.001 255.999 256-255.999-60.16-60.16-195.84 195.412-195.841-195.412z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chevron-down" ], @@ -971,15 +1115,15 @@ }, "attrs": [], "properties": { - "order": 610, - "id": 41, + "order": 1758, + "id": 40, "name": "chevron-down", "prevSize": 32, "code": 59661 }, "setIdx": 0, - "setId": 0, - "iconIdx": 39 + "setId": 2, + "iconIdx": 41 }, { "icon": { @@ -988,6 +1132,8 @@ ], "width": 1067, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chevron-left" ], @@ -996,15 +1142,15 @@ }, "attrs": [], "properties": { - "order": 611, - "id": 42, + "order": 1759, + "id": 41, "name": "chevron-left", "prevSize": 32, "code": 59662 }, "setIdx": 0, - "setId": 0, - "iconIdx": 40 + "setId": 2, + "iconIdx": 42 }, { "icon": { @@ -1012,6 +1158,8 @@ "M426.671 256l-60.16 60.16 195.414 195.84-195.414 195.84 60.16 60.16 256-256-256-256z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chevron-right" ], @@ -1020,15 +1168,15 @@ }, "attrs": [], "properties": { - "order": 612, - "id": 43, + "order": 1760, + "id": 42, "name": "chevron-right", "prevSize": 32, "code": 59663 }, "setIdx": 0, - "setId": 0, - "iconIdx": 41 + "setId": 2, + "iconIdx": 43 }, { "icon": { @@ -1036,6 +1184,8 @@ "M695.258 670.080l60.16-60.16-256-255.998-256.001 255.998 60.16 60.16 195.841-195.413 195.84 195.413z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "chevron-up" ], @@ -1044,15 +1194,15 @@ }, "attrs": [], "properties": { - "order": 613, - "id": 44, + "order": 1761, + "id": 43, "name": "chevron-up", "prevSize": 32, "code": 59664 }, "setIdx": 0, - "setId": 0, - "iconIdx": 42 + "setId": 2, + "iconIdx": 44 }, { "icon": { @@ -1060,6 +1210,8 @@ "M938.667 128h-640c-29.44 0-52.48 14.933-67.84 37.547l-230.827 346.453 230.827 346.027c15.36 22.613 38.4 37.973 67.84 37.973h640c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333zM810.667 665.173l-60.16 60.16-153.173-153.173-153.173 153.173-60.16-60.16 153.173-153.173-153.173-153.173 60.16-60.16 153.173 153.173 153.173-153.173 60.16 60.16-153.173 153.173 153.173 153.173z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clear" ], @@ -1068,15 +1220,15 @@ }, "attrs": [], "properties": { - "order": 614, - "id": 45, + "order": 1762, + "id": 44, "name": "clear", "prevSize": 32, "code": 59747 }, "setIdx": 0, - "setId": 0, - "iconIdx": 43 + "setId": 2, + "iconIdx": 45 }, { "icon": { @@ -1084,6 +1236,8 @@ "M777.481 169.752h-158.528c-21.619-66.56-86.852-100.693-144.879-76.8-32.614 12.8-56.888 40.96-69.025 76.8h-158.53c-20.117 0-39.41 8.99-53.635 24.994s-22.217 37.708-22.217 60.34v597.335c0 22.63 7.991 44.335 22.217 60.339s33.518 24.994 53.635 24.994h530.962c20.117 0 39.411-8.99 53.636-24.994s22.217-37.709 22.217-60.339v-597.335c0-22.632-7.991-44.337-22.217-60.34s-33.519-24.994-53.636-24.994zM512 169.752c10.057 0 19.703 4.495 26.816 12.497s11.11 18.854 11.11 30.17c0 11.316-3.998 22.168-11.11 30.17s-16.759 12.497-26.816 12.497c-10.057 0-19.703-4.495-26.816-12.497s-11.11-18.854-11.11-30.17c0-11.316 3.998-22.168 11.11-30.17s16.759-12.497 26.816-12.497zM322.371 340.419h379.257v-85.333h75.853v597.335h-530.962v-597.335h75.852v85.333zM701.628 511.087h-379.257v-85.335h379.257v85.335zM625.779 681.754h-303.409v-85.333h303.409v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clipboard" ], @@ -1092,15 +1246,15 @@ }, "attrs": [], "properties": { - "order": 615, - "id": 46, + "order": 1763, + "id": 45, "name": "clipboard", "prevSize": 32, "code": 59717 }, "setIdx": 0, - "setId": 0, - "iconIdx": 44 + "setId": 2, + "iconIdx": 46 }, { "icon": { @@ -1109,6 +1263,8 @@ "M533.333 298.667h-64v256l224 134.4 32-52.48-192-113.92v-224z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock" ], @@ -1117,15 +1273,15 @@ }, "attrs": [], "properties": { - "order": 616, - "id": 47, + "order": 1764, + "id": 46, "name": "clock", "prevSize": 32, "code": 59864 }, "setIdx": 0, - "setId": 0, - "iconIdx": 45 + "setId": 2, + "iconIdx": 47 }, { "icon": { @@ -1135,6 +1291,8 @@ "M810.667 597.333c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333c117.76 0 213.333-95.573 213.333-213.333s-95.573-213.333-213.333-213.333zM768 917.333l-106.667-106.667 30.080-30.080 76.587 76.373 161.92-161.92 30.080 30.293-192 192z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-available" ], @@ -1143,15 +1301,15 @@ }, "attrs": [], "properties": { - "order": 617, - "id": 48, + "order": 1765, + "id": 47, "name": "clock-available", "prevSize": 32, "code": 59848 }, "setIdx": 0, - "setId": 0, - "iconIdx": 46 + "setId": 2, + "iconIdx": 48 }, { "icon": { @@ -1161,6 +1319,8 @@ "M779.025 1012.54c-56.401 0-107.089-34.428-128.021-86.848l-52.42-131.657c-5.363-13.666 7.437-27.332 21.453-22.835l13.666 4.497c9.685 3.115 17.647 10.556 21.453 20.070l24.393 61.069h12.975v-203.277c0-11.938 9.69-21.628 21.623-21.628 11.938 0 21.628 9.69 21.628 21.628v151.377h17.301v-185.98c0-11.934 9.685-21.623 21.623-21.623s21.623 9.69 21.623 21.623v185.98h17.301v-160.026c0-11.938 9.69-21.628 21.628-21.628 11.934 0 21.623 9.69 21.623 21.628v160.026h17.301v-108.126c0-11.938 9.685-21.628 21.623-21.628s21.628 9.69 21.628 21.628v177.327c0 76.467-61.935 138.402-138.402 138.402z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-bid" ], @@ -1169,15 +1329,15 @@ }, "attrs": [], "properties": { - "order": 618, - "id": 49, + "order": 1766, + "id": 48, "name": "clock-bid", "prevSize": 32, "code": 59850 }, "setIdx": 0, - "setId": 0, - "iconIdx": 47 + "setId": 2, + "iconIdx": 49 }, { "icon": { @@ -1187,6 +1347,8 @@ "M640 910.234v71.1h71.1l209.702-209.702-71.1-71.1-209.702 209.702zM975.787 716.646c7.394-7.394 7.394-19.341 0-26.735l-44.365-44.365c-7.394-7.394-19.341-7.394-26.735 0l-34.697 34.697 71.1 71.1 34.697-34.697z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-edit" ], @@ -1195,15 +1357,15 @@ }, "attrs": [], "properties": { - "order": 619, - "id": 50, + "order": 1767, + "id": 49, "name": "clock-edit", "prevSize": 32, "code": 59852 }, "setIdx": 0, - "setId": 0, - "iconIdx": 48 + "setId": 2, + "iconIdx": 50 }, { "icon": { @@ -1211,24 +1373,30 @@ "M487.505 24.518c-268.115 0-487.482 219.367-487.482 487.482s219.367 487.482 487.482 487.482 487.482-219.367 487.482-487.482-219.367-487.482-487.482-487.482zM660.561 697.243l-199.056-122.277c-14.625-8.938-23.156-24.374-23.156-41.436v-228.709c0.407-20.311 17.061-36.561 36.968-36.561 20.311 0 36.561 16.25 36.561 36.561v216.929l186.868 112.528c17.875 10.969 23.562 33.716 12.999 51.185-6.736 10.495-18.346 17.351-31.557 17.351-7.266 0-14.047-2.074-19.785-5.661l0.157 0.091z" ], "width": 975, - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock filled" ], "defaultCode": 59764, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 620, - "id": 51, + "order": 1768, + "id": 50, "name": "clock-filled", "prevSize": 32, "code": 59787 }, "setIdx": 0, - "setId": 0, - "iconIdx": 49 + "setId": 2, + "iconIdx": 51 }, { "icon": { @@ -1237,6 +1405,8 @@ "M533.333 298.667h-64v256l224 134.4 32-52.48-192-113.92v-224z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-flexible" ], @@ -1245,15 +1415,15 @@ }, "attrs": [], "properties": { - "order": 621, - "id": 52, + "order": 1769, + "id": 51, "name": "clock-flexible", "prevSize": 32, "code": 59853 }, "setIdx": 0, - "setId": 0, - "iconIdx": 50 + "setId": 2, + "iconIdx": 52 }, { "icon": { @@ -1263,6 +1433,8 @@ "M810.667 1024c117.82 0 213.333-95.514 213.333-213.333s-95.514-213.333-213.333-213.333c-117.82 0-213.333 95.514-213.333 213.333s95.514 213.333 213.333 213.333zM682.667 853.333c23.565 0 42.667-19.102 42.667-42.667s-19.102-42.667-42.667-42.667c-23.565 0-42.667 19.102-42.667 42.667s19.102 42.667 42.667 42.667zM853.333 810.667c0 23.565-19.102 42.667-42.667 42.667s-42.667-19.102-42.667-42.667c0-23.565 19.102-42.667 42.667-42.667s42.667 19.102 42.667 42.667zM938.667 853.333c23.565 0 42.667-19.102 42.667-42.667s-19.102-42.667-42.667-42.667c-23.565 0-42.667 19.102-42.667 42.667s19.102 42.667 42.667 42.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-in-progress" ], @@ -1271,15 +1443,15 @@ }, "attrs": [], "properties": { - "order": 622, - "id": 53, + "order": 1770, + "id": 52, "name": "clock-in-progress", "prevSize": 32, "code": 59854 }, "setIdx": 0, - "setId": 0, - "iconIdx": 51 + "setId": 2, + "iconIdx": 53 }, { "icon": { @@ -1289,6 +1461,8 @@ "M810.667 597.333c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333c117.76 0 213.333-95.573 213.333-213.333s-95.573-213.333-213.333-213.333zM832 917.333h-42.667v-128h42.667v128zM832 746.667h-42.667v-42.667h42.667v42.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-info" ], @@ -1297,15 +1471,15 @@ }, "attrs": [], "properties": { - "order": 623, - "id": 54, + "order": 1771, + "id": 53, "name": "clock-info", "prevSize": 32, "code": 59855 }, "setIdx": 0, - "setId": 0, - "iconIdx": 52 + "setId": 2, + "iconIdx": 54 }, { "icon": { @@ -1315,6 +1489,8 @@ "M810.667 597.333c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333c117.76 0 213.333-95.573 213.333-213.333s-95.573-213.333-213.333-213.333zM832 960h-42.667v-42.667h42.667v42.667zM876.16 794.667l-19.2 19.627c-15.36 15.573-24.96 28.373-24.96 60.373h-42.667v-10.667c0-23.467 9.6-44.8 24.96-60.373l26.453-26.88c7.893-7.68 12.587-18.347 12.587-30.080 0-23.467-19.2-42.667-42.667-42.667s-42.667 19.2-42.667 42.667h-42.667c0-47.147 38.187-85.333 85.333-85.333s85.333 38.187 85.333 85.333c0 18.773-7.68 35.84-19.84 48z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-missed" ], @@ -1323,15 +1499,15 @@ }, "attrs": [], "properties": { - "order": 624, - "id": 55, + "order": 1772, + "id": 54, "name": "clock-missed", "prevSize": 32, "code": 59856 }, "setIdx": 0, - "setId": 0, - "iconIdx": 53 + "setId": 2, + "iconIdx": 55 }, { "icon": { @@ -1341,6 +1517,8 @@ "M810.667 597.333c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333c117.76 0 213.333-95.573 213.333-213.333s-95.573-213.333-213.333-213.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-on" ], @@ -1349,15 +1527,15 @@ }, "attrs": [], "properties": { - "order": 625, - "id": 56, + "order": 1773, + "id": 55, "name": "clock-on", "prevSize": 32, "code": 59857 }, "setIdx": 0, - "setId": 0, - "iconIdx": 54 + "setId": 2, + "iconIdx": 56 }, { "icon": { @@ -1367,6 +1545,8 @@ "M85.333 512c0-235.52 190.72-426.667 426.24-426.667 235.947 0 427.093 191.147 427.093 426.667h-85.333c0-188.587-152.747-341.333-341.333-341.333s-341.333 152.747-341.333 341.333c0 188.587 152.747 341.333 341.333 341.333v85.333c-0.141 0-0.286 0-0.427 0-235.52 0-426.24-191.147-426.24-426.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-rollover" ], @@ -1375,15 +1555,15 @@ }, "attrs": [], "properties": { - "order": 626, - "id": 57, + "order": 1774, + "id": 56, "name": "clock-rollover", "prevSize": 32, "code": 59858 }, "setIdx": 0, - "setId": 0, - "iconIdx": 55 + "setId": 2, + "iconIdx": 57 }, { "icon": { @@ -1391,6 +1571,8 @@ "M692.907 331.093c-49.92-49.92-115.2-75.093-180.907-75.093v256l-180.907 180.907c99.84 99.84 261.973 99.84 362.24 0 99.84-99.84 99.84-261.973-0.427-361.813zM512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM512 853.333c-188.587 0-341.333-152.747-341.333-341.333s152.747-341.333 341.333-341.333c188.587 0 341.333 152.747 341.333 341.333s-152.747 341.333-341.333 341.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-segment" ], @@ -1399,15 +1581,15 @@ }, "attrs": [], "properties": { - "order": 627, - "id": 58, + "order": 1775, + "id": 57, "name": "clock-segment", "prevSize": 32, "code": 59859 }, "setIdx": 0, - "setId": 0, - "iconIdx": 56 + "setId": 2, + "iconIdx": 58 }, { "icon": { @@ -1417,6 +1599,8 @@ "M511.573 85.333c-235.52 0-426.24 191.147-426.24 426.667s190.72 426.667 426.24 426.667c25.165 0 49.822-2.176 73.792-6.345-13.589-25.109-23.1-52.745-27.648-82.022-14.955 2.001-30.217 3.034-45.717 3.034-188.587 0-341.333-152.747-341.333-341.333s152.747-341.333 341.333-341.333c188.587 0 341.333 152.747 341.333 341.333 0 15.501-1.033 30.763-3.034 45.717 29.295 4.553 56.947 14.071 82.069 27.674 4.139-23.846 6.298-48.367 6.298-73.391 0-235.52-191.147-426.667-427.093-426.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-start" ], @@ -1425,15 +1609,15 @@ }, "attrs": [], "properties": { - "order": 628, - "id": 59, + "order": 1776, + "id": 58, "name": "clock-start", "prevSize": 32, "code": 59860 }, "setIdx": 0, - "setId": 0, - "iconIdx": 57 + "setId": 2, + "iconIdx": 59 }, { "icon": { @@ -1443,6 +1627,8 @@ "M85.333 512c0-235.52 190.72-426.667 426.24-426.667 235.947 0 427.093 191.147 427.093 426.667 0 25.024-2.159 49.545-6.298 73.391-25.122-13.602-52.774-23.121-82.069-27.674 2.001-14.955 3.034-30.217 3.034-45.717 0-188.587-152.747-341.333-341.333-341.333s-341.333 152.747-341.333 341.333c0 188.587 152.747 341.333 341.333 341.333 15.501 0 30.763-1.033 45.717-3.034 4.548 29.278 14.059 56.913 27.648 82.022-23.97 4.169-48.627 6.345-73.792 6.345-235.52 0-426.24-191.147-426.24-426.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-stop" ], @@ -1451,15 +1637,15 @@ }, "attrs": [], "properties": { - "order": 629, - "id": 60, + "order": 1777, + "id": 59, "name": "clock-stop", "prevSize": 32, "code": 59861 }, "setIdx": 0, - "setId": 0, - "iconIdx": 58 + "setId": 2, + "iconIdx": 60 }, { "icon": { @@ -1470,6 +1656,8 @@ "M85.333 512c0-235.52 190.72-426.667 426.24-426.667 235.947 0 427.093 191.147 427.093 426.667 0 25.024-2.159 49.545-6.298 73.391-25.122-13.602-52.774-23.121-82.069-27.674 2.001-14.955 3.034-30.217 3.034-45.717 0-188.587-152.747-341.333-341.333-341.333s-341.333 152.747-341.333 341.333c0 188.587 152.747 341.333 341.333 341.333 15.501 0 30.763-1.033 45.717-3.034 4.548 29.278 14.059 56.913 27.648 82.022-23.97 4.169-48.627 6.345-73.792 6.345-235.52 0-426.24-191.147-426.24-426.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-switch" ], @@ -1478,15 +1666,15 @@ }, "attrs": [], "properties": { - "order": 630, - "id": 61, + "order": 1778, + "id": 60, "name": "clock-switch", "prevSize": 32, "code": 59862 }, "setIdx": 0, - "setId": 0, - "iconIdx": 59 + "setId": 2, + "iconIdx": 61 }, { "icon": { @@ -1494,6 +1682,8 @@ "M640 42.667h-256v85.333h256v-85.333zM469.333 597.333h85.333v-256h-85.333v256zM811.947 315.307l60.587-60.587c-18.347-21.76-38.4-42.24-60.16-60.16l-60.587 60.587c-66.133-52.907-149.333-84.48-239.787-84.48-212.053 0-384 171.947-384 384s171.52 384 384 384c212.48 0 384-171.947 384-384 0-90.453-31.573-173.653-84.053-239.36zM512 853.333c-165.12 0-298.667-133.547-298.667-298.667s133.547-298.667 298.667-298.667c165.12 0 298.667 133.547 298.667 298.667s-133.547 298.667-298.667 298.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "clock-timer" ], @@ -1502,15 +1692,15 @@ }, "attrs": [], "properties": { - "order": 631, - "id": 62, + "order": 1779, + "id": 61, "name": "clock-timer", "prevSize": 32, "code": 59863 }, "setIdx": 0, - "setId": 0, - "iconIdx": 60 + "setId": 2, + "iconIdx": 62 }, { "icon": { @@ -1518,6 +1708,8 @@ "M896 204.227l-77.35-76.227-306.65 302.208-306.651-302.208-77.349 76.227 306.65 302.209-306.65 302.204 77.349 76.228 306.651-302.208 306.65 302.208 77.35-76.228-306.65-302.204 306.65-302.209z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "close" ], @@ -1526,15 +1718,15 @@ }, "attrs": [], "properties": { - "order": 632, - "id": 63, + "order": 1780, + "id": 62, "name": "close", "prevSize": 32, "code": 59665 }, "setIdx": 0, - "setId": 0, - "iconIdx": 61 + "setId": 2, + "iconIdx": 63 }, { "icon": { @@ -1542,6 +1734,8 @@ "M554.667 938.667c235.639 0 426.667-191.027 426.667-426.667 0-235.642-191.027-426.667-426.667-426.667-235.642 0-426.667 191.025-426.667 426.667 0 235.639 191.025 426.667 426.667 426.667zM725.030 298.667l42.97 42.971-170.364 170.362 170.364 170.364-42.97 42.97-170.364-170.364-170.362 170.364-42.971-42.97 170.364-170.364-170.364-170.362 42.971-42.971 170.362 170.364 170.364-170.364z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "close circle" ], @@ -1550,15 +1744,15 @@ }, "attrs": [], "properties": { - "order": 633, - "id": 64, + "order": 1781, + "id": 63, "name": "close-circle", "prevSize": 32, "code": 59716 }, "setIdx": 0, - "setId": 0, - "iconIdx": 62 + "setId": 2, + "iconIdx": 64 }, { "icon": { @@ -1566,6 +1760,8 @@ "M825.6 428.373c-29.013-147.2-158.293-257.707-313.6-257.707-123.307 0-230.4 69.973-283.733 172.373-128.427 13.653-228.267 122.453-228.267 254.293 0 141.227 114.773 256 256 256h554.667c117.76 0 213.333-95.573 213.333-213.333 0-112.64-87.467-203.947-198.4-211.627zM725.333 554.667l-213.333 213.333-213.333-213.333h128v-170.667h170.667v170.667h128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "cloud-download" ], @@ -1574,15 +1770,15 @@ }, "attrs": [], "properties": { - "order": 634, - "id": 65, + "order": 1782, + "id": 64, "name": "cloud-download", "prevSize": 32, "code": 59865 }, "setIdx": 0, - "setId": 0, - "iconIdx": 63 + "setId": 2, + "iconIdx": 65 }, { "icon": { @@ -1590,6 +1786,8 @@ "M1024 640c0-112.64-87.467-203.947-198.4-211.627-29.013-147.2-158.293-257.707-313.6-257.707-56.747 0-109.654 15.36-155.734 41.387l63.573 63.573c28.588-12.373 59.308-19.627 92.161-19.627 129.707 0 234.667 104.96 234.667 234.667v21.333h64c70.827 0 128 57.173 128 128 0 42.24-20.48 78.933-51.627 102.4l60.16 60.16c46.507-39.253 76.8-96.853 76.8-162.56zM158.292 194.56c-16.64 16.64-16.64 43.52 0 60.16l87.893 87.893h-17.92c-139.947 14.933-245.76 142.507-225.707 289.707 17.067 128.853 133.547 221.013 262.827 221.013h491.094l55.040 55.040c16.64 16.64 43.52 16.64 60.16 0s16.64-43.52 0-60.16l-653.228-653.653c-16.64-16.64-43.52-16.64-60.16 0zM255.999 768c-94.293 0-170.667-76.373-170.667-170.667s76.373-170.667 170.667-170.667h73.813l341.334 341.333h-415.148z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "cloud-off" ], @@ -1598,15 +1796,15 @@ }, "attrs": [], "properties": { - "order": 635, - "id": 66, + "order": 1783, + "id": 65, "name": "cloud-off", "prevSize": 32, "code": 59748 }, "setIdx": 0, - "setId": 0, - "iconIdx": 64 + "setId": 2, + "iconIdx": 66 }, { "icon": { @@ -1614,6 +1812,8 @@ "M825.6 428.373c-29.013-147.2-158.293-257.707-313.6-257.707-123.307 0-230.4 69.973-283.733 172.373-128.427 13.653-228.267 122.453-228.267 254.293 0 141.227 114.773 256 256 256h554.667c117.76 0 213.333-95.573 213.333-213.333 0-112.64-87.467-203.947-198.4-211.627zM597.333 554.667v170.667h-170.667v-170.667h-128l213.333-213.333 213.333 213.333h-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "cloud-upload" ], @@ -1622,15 +1822,15 @@ }, "attrs": [], "properties": { - "order": 636, - "id": 67, + "order": 1784, + "id": 66, "name": "cloud-upload", "prevSize": 32, "code": 59866 }, "setIdx": 0, - "setId": 0, - "iconIdx": 65 + "setId": 2, + "iconIdx": 67 }, { "icon": { @@ -1638,6 +1838,8 @@ "M512 85.333c-235.699 0-426.667 190.968-426.667 426.667s190.968 426.667 426.667 426.667c235.699 0 426.667-190.967 426.667-426.667s-190.967-426.667-426.667-426.667zM512 856.085c-189.763 0-344.086-154.321-344.086-344.085s154.323-344.086 344.086-344.086c189.764 0 344.085 154.323 344.085 344.086s-154.321 344.085-344.085 344.085zM512 608.346c-57.805 0-112.172 25.459-149.333 69.85-14.624 17.549-12.215 43.524 5.333 58.15 17.548 14.622 43.527 12.386 58.15-5.163 42.667-51.098 129.033-51.098 171.699 0 13.935 16.687 39.915 20.471 58.15 5.163 17.549-14.626 19.785-40.602 5.333-58.15-37.163-44.39-91.529-69.85-149.333-69.85zM429.419 484.471c17.719 0 34.236-11.524 39.569-29.419 6.541-21.85-5.85-44.902-27.699-51.44l-137.632-41.29c-22.022-6.71-44.903 5.849-51.441 27.699s5.85 44.901 27.699 51.442l48.516 14.622c-5.333 8.431-9.118 17.894-9.118 28.561 0 30.451 24.602 55.053 55.054 55.053s55.053-24.777 55.053-55.228zM771.785 390.022c-6.537-21.85-29.419-34.237-51.439-27.699l-137.634 41.29c-21.85 6.537-34.24 29.59-27.699 51.44 5.333 17.894 21.85 29.419 39.569 29.419 0 30.451 24.602 55.057 55.053 55.057s55.053-24.606 55.053-55.057c0-10.667-3.785-20.126-9.118-28.557l48.516-14.626c21.85-6.366 34.236-29.417 27.699-51.267z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "complaint" ], @@ -1646,15 +1848,15 @@ }, "attrs": [], "properties": { - "order": 637, - "id": 68, + "order": 1785, + "id": 67, "name": "complaint", "prevSize": 32, "code": 59666 }, "setIdx": 0, - "setId": 0, - "iconIdx": 66 + "setId": 2, + "iconIdx": 68 }, { "icon": { @@ -1662,6 +1864,8 @@ "M682.667 42.667h-512c-46.933 0-85.333 38.4-85.333 85.333v597.333h85.333v-597.333h512v-85.333zM810.667 213.333h-469.333c-46.933 0-85.333 38.4-85.333 85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h469.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333zM810.667 896h-469.333v-597.333h469.333v597.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "copy" ], @@ -1670,15 +1874,15 @@ }, "attrs": [], "properties": { - "order": 638, - "id": 69, + "order": 1786, + "id": 68, "name": "copy", "prevSize": 32, "code": 59750 }, "setIdx": 0, - "setId": 0, - "iconIdx": 67 + "setId": 2, + "iconIdx": 69 }, { "icon": { @@ -1686,6 +1890,8 @@ "M128 554.667h341.333v-426.667h-341.333v426.667zM128 896h341.333v-256h-341.333v256zM554.667 896h341.333v-426.667h-341.333v426.667zM554.667 128v256h341.333v-256h-341.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "dashboard" ], @@ -1694,15 +1900,44 @@ }, "attrs": [], "properties": { - "order": 639, - "id": 70, + "order": 1787, + "id": 69, "name": "dashboard", "prevSize": 32, "code": 59751 }, "setIdx": 0, - "setId": 0, - "iconIdx": 68 + "setId": 2, + "iconIdx": 70 + }, + { + "icon": { + "paths": [ + "M272.852 320c-53.454 0-80.223 64.628-42.426 102.426l239.148 239.148c23.432 23.432 61.42 23.432 84.852 0l239.148-239.148c37.798-37.798 11.028-102.426-42.426-102.426h-478.296z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "decrease" + ], + "grid": 16 + }, + "attrs": [ + {} + ], + "properties": { + "order": 1788, + "id": 70, + "name": "decrease", + "prevSize": 32, + "code": 59745 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 71 }, { "icon": { @@ -1710,6 +1945,8 @@ "M256 810.667c0 46.933 38.4 85.333 85.333 85.333h341.333c46.933 0 85.333-38.4 85.333-85.333v-512h-512v512zM810.667 170.667h-149.333l-42.667-42.667h-213.333l-42.667 42.667h-149.333v85.333h597.333v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "delete" ], @@ -1718,15 +1955,15 @@ }, "attrs": [], "properties": { - "order": 641, - "id": 72, + "order": 1789, + "id": 71, "name": "delete", "prevSize": 32, "code": 59667 }, "setIdx": 0, - "setId": 0, - "iconIdx": 69 + "setId": 2, + "iconIdx": 72 }, { "icon": { @@ -1734,6 +1971,8 @@ "M128 554.664h85.333v-85.334h-85.333v85.334zM128 725.331h85.333v-85.334h-85.333v85.334zM128 383.997h85.333v-85.333h-85.333v85.333zM298.667 554.664h597.333v-85.334h-597.333v85.334zM298.667 725.331h597.333v-85.334h-597.333v85.334zM298.667 298.664v85.333h597.333v-85.333h-597.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "details" ], @@ -1742,15 +1981,15 @@ }, "attrs": [], "properties": { - "order": 642, - "id": 73, + "order": 1790, + "id": 72, "name": "details", "prevSize": 32, "code": 59668 }, "setIdx": 0, - "setId": 0, - "iconIdx": 70 + "setId": 2, + "iconIdx": 73 }, { "icon": { @@ -1758,6 +1997,8 @@ "M512 810.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM256 42.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM256 298.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM256 554.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM768 213.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM512 554.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM768 554.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM768 298.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM512 298.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM512 42.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "dialpad" ], @@ -1766,15 +2007,15 @@ }, "attrs": [], "properties": { - "order": 643, - "id": 74, + "order": 1791, + "id": 73, "name": "dialpad", "prevSize": 32, "code": 59867 }, "setIdx": 0, - "setId": 0, - "iconIdx": 71 + "setId": 2, + "iconIdx": 74 }, { "icon": { @@ -1782,6 +2023,8 @@ "M810.667 384h-170.667v-256h-256v256h-170.667l298.667 298.667 298.667-298.667zM213.333 768v85.333h597.333v-85.333h-597.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "download" ], @@ -1790,15 +2033,15 @@ }, "attrs": [], "properties": { - "order": 644, - "id": 75, + "order": 1792, + "id": 74, "name": "download", "prevSize": 32, "code": 59868 }, "setIdx": 0, - "setId": 0, - "iconIdx": 72 + "setId": 2, + "iconIdx": 75 }, { "icon": { @@ -1806,6 +2049,8 @@ "M128 736.004v160h160l471.893-471.895-160-160-471.893 471.895zM883.627 300.376c16.64-16.64 16.64-43.52 0-60.16l-99.84-99.84c-16.64-16.64-43.52-16.64-60.16 0l-78.080 78.080 160 160 78.080-78.080z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "edit" ], @@ -1814,15 +2059,15 @@ }, "attrs": [], "properties": { - "order": 645, - "id": 76, + "order": 1793, + "id": 75, "name": "edit", "prevSize": 32, "code": 59670 }, "setIdx": 0, - "setId": 0, - "iconIdx": 73 + "setId": 2, + "iconIdx": 76 }, { "icon": { @@ -1830,6 +2075,8 @@ "M750.080 266.667l75.52 75.52-212.48 212.48h-75.52v-75.52l212.48-212.48zM889.6 247.893l-45.227-45.227c-8.533-8.533-21.76-8.533-30.293 0l-36.267 36.267 75.52 75.52 36.267-36.267c8.533-8.533 8.533-22.187 0-30.293zM768 520.533v204.8h85.333v85.333h-682.667v-85.333h85.333v-298.667c0-119.040 81.493-219.307 192-247.467v-29.867c0-35.413 28.587-64 64-64s64 28.587 64 64v29.867c34.987 8.96 66.987 25.173 94.293 46.507l-218.027 218.027v196.267h196.267l119.467-119.467zM426.667 853.333h170.667c0 46.933-38.4 85.333-85.333 85.333s-85.333-38.4-85.333-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "edit-notifications" ], @@ -1838,15 +2085,15 @@ }, "attrs": [], "properties": { - "order": 646, - "id": 77, + "order": 1794, + "id": 76, "name": "edit-notifications", "prevSize": 32, "code": 59725 }, "setIdx": 0, - "setId": 0, - "iconIdx": 74 + "setId": 2, + "iconIdx": 77 }, { "icon": { @@ -1854,6 +2101,8 @@ "M785.067 452.267c-78.933-68.693-181.333-110.933-294.4-110.933-198.398 0-366.078 129.28-424.958 308.053l100.693 33.28c44.8-136.107 172.8-234.667 324.265-234.667 83.2 0 159.147 30.72 218.453 80.213l-154.453 154.453h384v-384l-153.6 153.6z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "edit-redo" ], @@ -1862,15 +2111,15 @@ }, "attrs": [], "properties": { - "order": 647, - "id": 78, + "order": 1795, + "id": 77, "name": "edit-redo", "prevSize": 32, "code": 59752 }, "setIdx": 0, - "setId": 0, - "iconIdx": 75 + "setId": 2, + "iconIdx": 78 }, { "icon": { @@ -1878,6 +2127,8 @@ "M533.333 341.333c-113.067 0-215.467 42.24-294.4 110.933l-153.6-153.6v384h384l-154.453-154.453c59.307-49.493 134.827-80.213 218.453-80.213 151.040 0 279.467 98.56 324.267 234.667l101.12-33.28c-59.307-178.773-226.987-308.053-425.387-308.053z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "edit-undo" ], @@ -1886,15 +2137,15 @@ }, "attrs": [], "properties": { - "order": 648, - "id": 79, + "order": 1796, + "id": 78, "name": "edit-undo", "prevSize": 32, "code": 59753 }, "setIdx": 0, - "setId": 0, - "iconIdx": 76 + "setId": 2, + "iconIdx": 79 }, { "icon": { @@ -1902,6 +2153,8 @@ "M853.333 170.667h-682.667c-46.933 0-84.907 38.4-84.907 85.333l-0.427 512c0 46.933 38.4 85.333 85.333 85.333h682.667c46.933 0 85.333-38.4 85.333-85.333v-512c0-46.933-38.4-85.333-85.333-85.333zM853.333 341.333l-341.333 213.333-341.333-213.333v-85.333l341.333 213.333 341.333-213.333v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "email" ], @@ -1910,15 +2163,15 @@ }, "attrs": [], "properties": { - "order": 649, - "id": 80, + "order": 1797, + "id": 79, "name": "email", "prevSize": 32, "code": 59872 }, "setIdx": 0, - "setId": 0, - "iconIdx": 77 + "setId": 2, + "iconIdx": 80 }, { "icon": { @@ -1926,6 +2179,8 @@ "M597.333 384v-170.667l298.667 298.667-298.667 298.667v-174.933c-213.333 0-362.667 68.267-469.333 217.6 42.667-213.333 170.667-426.667 469.333-469.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "email-forward" ], @@ -1934,15 +2189,15 @@ }, "attrs": [], "properties": { - "order": 650, - "id": 81, + "order": 1798, + "id": 80, "name": "email-forward", "prevSize": 32, "code": 59869 }, "setIdx": 0, - "setId": 0, - "iconIdx": 78 + "setId": 2, + "iconIdx": 81 }, { "icon": { @@ -1950,6 +2205,8 @@ "M426.667 384v-170.667l-298.667 298.667 298.667 298.667v-174.933c213.333 0 362.667 68.267 469.333 217.6-42.667-213.333-170.667-426.667-469.333-469.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "email-reply" ], @@ -1958,15 +2215,15 @@ }, "attrs": [], "properties": { - "order": 651, - "id": 82, + "order": 1799, + "id": 81, "name": "email-reply", "prevSize": 32, "code": 59871 }, "setIdx": 0, - "setId": 0, - "iconIdx": 79 + "setId": 2, + "iconIdx": 82 }, { "icon": { @@ -1974,6 +2231,8 @@ "M298.667 341.333v-128l-298.667 298.667 298.667 298.667v-128l-170.667-170.667 170.667-170.667zM554.667 384v-170.667l-298.667 298.667 298.667 298.667v-174.933c213.333 0 362.667 68.267 469.333 217.6-42.667-213.333-170.667-426.667-469.333-469.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "email-reply-all" ], @@ -1982,38 +2241,44 @@ }, "attrs": [], "properties": { - "order": 652, - "id": 83, + "order": 1800, + "id": 82, "name": "email-reply-all", "prevSize": 32, "code": 59870 }, "setIdx": 0, - "setId": 0, - "iconIdx": 80 + "setId": 2, + "iconIdx": 83 }, { "icon": { "paths": [ "M119.893 119.893l-60.587 60.16 96.853 96.853c-44.372 65.848-70.827 146.966-70.827 234.263 0 0.292 0 0.584 0.001 0.875l-0-0.045c0 235.52 191.147 426.667 426.667 426.667 87.040 0 167.68-26.027 235.093-70.827l96.853 96.853 60.16-60.587-784.213-784.213zM512 853.333c-188.16 0-341.333-153.173-341.333-341.333 0-63.147 17.493-122.027 47.787-173.227l466.347 466.773c-49.283 30.017-108.886 47.787-172.64 47.787-0.056 0-0.112-0-0.169-0l0.009 0zM512 170.667c188.16 0 341.333 153.173 341.333 341.333 0 63.147-17.493 122.027-47.787 172.8l61.867 61.867c44.626-65.427 71.256-146.225 71.256-233.242 0-0.501-0.001-1.002-0.003-1.502l0 0.078c0-235.52-191.147-426.667-426.667-426.667-87.040 0-167.68 26.027-235.093 70.827l61.867 61.867c51.2-29.867 110.080-47.36 173.227-47.36z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "empty" ], "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 653, - "id": 84, + "order": 1801, + "id": 83, "name": "empty", "prevSize": 32, "code": 59802 }, "setIdx": 0, - "setId": 0, - "iconIdx": 81 + "setId": 2, + "iconIdx": 84 }, { "icon": { @@ -2021,24 +2286,32 @@ "M634.88 430.080c0 32.768-12.288 61.44-36.864 86.016s-53.248 36.864-86.016 36.864c-32.768 0-61.44-12.288-86.016-36.864s-36.864-53.248-36.864-86.016c0-32.768 12.288-61.44 36.864-86.016s53.248-32.768 86.016-32.768c32.768 0 61.44 12.288 86.016 32.768s36.864 49.152 36.864 86.016z", "M167.936 61.44v61.44h688.128v-61.44h-688.128zM167.936 901.12v61.44h688.128v-61.44h-688.128zM913.408 204.8c-12.288-12.288-28.672-20.48-40.96-20.48h-716.8c-16.384 0-32.768 4.096-40.96 16.384-12.288 12.288-20.48 28.672-20.48 45.056v532.48c0 16.384 8.192 32.768 20.48 40.96s28.672 20.48 40.96 20.48h712.704c16.384 0 32.768-8.192 40.96-20.48s20.48-24.576 20.48-40.96v-532.48c0-16.384-8.192-32.768-16.384-40.96zM868.352 778.24h-90.112c-32.768-40.96-73.728-73.728-122.88-98.304-49.152-20.48-98.304-32.768-143.36-32.768s-94.208 12.288-143.36 32.768c-49.152 20.48-90.112 53.248-122.88 98.304h-90.112v-532.48h712.704v532.48z" ], - "attrs": [], + "attrs": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "ess" ], "defaultCode": 59727, "grid": 16 }, - "attrs": [], + "attrs": [ + {}, + {} + ], "properties": { - "order": 654, - "id": 85, + "order": 1802, + "id": 84, "name": "ess", "prevSize": 32, "code": 59727 }, "setIdx": 0, - "setId": 0, - "iconIdx": 82 + "setId": 2, + "iconIdx": 85 }, { "icon": { @@ -2046,6 +2319,8 @@ "M877.714 18.286c-12.108 0.010-23.066 4.922-31 12.857l-815.571 815.571c-7.923 7.939-12.822 18.897-12.822 31s4.899 23.061 12.823 31.001l-0.001-0.001c7.939 7.923 18.897 12.822 31 12.822s23.061-4.899 31.001-12.823l-0.001 0.001 815.571-815.571c7.923-7.939 12.822-18.897 12.822-31s-4.899-23.061-12.823-31.001l0.001 0.001c-7.934-7.936-18.892-12.847-30.998-12.857l-0.002-0zM936.286 321.857c-0.032-0-0.070-0-0.108-0-12.12 0-23.093 4.913-31.035 12.857l-570.429 570.429c-7.965 7.946-12.893 18.933-12.893 31.071s4.928 23.126 12.893 31.071l0.001 0.001c7.939 7.923 18.897 12.822 31 12.822s23.061-4.899 31.001-12.823l-0.001 0.001 570.571-570.571c7.923-7.939 12.822-18.897 12.822-31s-4.899-23.061-12.823-31.001l0.001 0.001c-7.934-7.936-18.892-12.847-30.998-12.857l-0.002-0z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "expand" ], @@ -2054,15 +2329,15 @@ }, "attrs": [], "properties": { - "order": 655, - "id": 86, + "order": 1803, + "id": 85, "name": "expand", "prevSize": 32, "code": 59669 }, "setIdx": 0, - "setId": 0, - "iconIdx": 83 + "setId": 2, + "iconIdx": 86 }, { "icon": { @@ -2070,6 +2345,8 @@ "M810.667 128h-597.333c-47.36 0-85.333 38.4-85.333 85.333v597.333c0 46.933 37.973 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-37.973-85.333-85.333-85.333zM810.667 810.667h-597.333v-512h597.333v512zM576 554.667c0 35.413-28.587 64-64 64s-64-28.587-64-64c0-35.413 28.587-64 64-64s64 28.587 64 64zM512 384c-116.48 0-215.893 70.827-256 170.667 40.107 99.84 139.52 170.667 256 170.667s215.893-70.827 256-170.667c-40.107-99.84-139.52-170.667-256-170.667zM512 661.333c-58.88 0-106.667-47.787-106.667-106.667s47.787-106.667 106.667-106.667c58.88 0 106.667 47.787 106.667 106.667s-47.787 106.667-106.667 106.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "eye-preview" ], @@ -2078,15 +2355,15 @@ }, "attrs": [], "properties": { - "order": 656, - "id": 87, + "order": 1804, + "id": 86, "name": "eye-preview", "prevSize": 32, "code": 59754 }, "setIdx": 0, - "setId": 0, - "iconIdx": 84 + "setId": 2, + "iconIdx": 87 }, { "icon": { @@ -2094,6 +2371,8 @@ "M512 192c-213.333 0-395.52 132.693-469.333 320 73.813 187.307 256 320 469.333 320s395.52-132.693 469.333-320c-73.813-187.307-256-320-469.333-320zM512 725.333c-117.76 0-213.333-95.573-213.333-213.333s95.573-213.333 213.333-213.333c117.76 0 213.333 95.573 213.333 213.333s-95.573 213.333-213.333 213.333zM512 384c-70.827 0-128 57.173-128 128s57.173 128 128 128c70.827 0 128-57.173 128-128s-57.173-128-128-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "eye-view" ], @@ -2102,40 +2381,15 @@ }, "attrs": [], "properties": { - "order": 657, - "id": 88, + "order": 1805, + "id": 87, "name": "eye-view", "prevSize": 32, "code": 59755 }, "setIdx": 0, - "setId": 0, - "iconIdx": 85 - }, - { - "icon": { - "paths": [ - "M838.857 217.143c21.143 21.143 38.857 63.429 38.857 93.714v658.286c0 30.286-24.571 54.857-54.857 54.857h-768c-30.286 0-54.857-24.571-54.857-54.857v-914.286c0-30.286 24.571-54.857 54.857-54.857h512c30.286 0 72.571 17.714 93.714 38.857zM585.143 77.714v214.857h214.857c-3.429-9.714-8.571-19.429-12.571-23.429l-178.857-178.857c-4-4-13.714-9.143-23.429-12.571zM804.571 950.857v-585.143h-237.714c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-438.857v877.714h731.429z" - ], - "width": 877.7142857142857, - "attrs": [], - "tags": [ - "file-o" - ], - "defaultCode": 61462, - "grid": 16 - }, - "attrs": [], - "properties": { - "name": "file", - "id": 94, - "order": 663, - "prevSize": 32, - "code": 61462 - }, - "setIdx": 0, - "setId": 0, - "iconIdx": 86 + "setId": 2, + "iconIdx": 88 }, { "icon": { @@ -2144,6 +2398,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-archive-o", "file-zip-o" @@ -2153,15 +2409,15 @@ }, "attrs": [], "properties": { - "name": "file-archive", - "id": 89, - "order": 658, + "name": "file-archive-o", + "id": 88, + "order": 1806, "prevSize": 32, "code": 61894 }, "setIdx": 0, - "setId": 0, - "iconIdx": 87 + "setId": 2, + "iconIdx": 89 }, { "icon": { @@ -2170,6 +2426,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-audio-o", "file-sound-o" @@ -2179,15 +2437,15 @@ }, "attrs": [], "properties": { - "name": "file-audio", - "id": 90, - "order": 659, + "name": "file-audio-o", + "id": 89, + "order": 1807, "prevSize": 32, "code": 61895 }, "setIdx": 0, - "setId": 0, - "iconIdx": 88 + "setId": 2, + "iconIdx": 90 }, { "icon": { @@ -2196,6 +2454,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-code-o" ], @@ -2204,15 +2464,15 @@ }, "attrs": [], "properties": { - "name": "file-code", - "id": 91, - "order": 660, + "name": "file-code-o", + "id": 90, + "order": 1808, "prevSize": 32, "code": 61897 }, "setIdx": 0, - "setId": 0, - "iconIdx": 89 + "setId": 2, + "iconIdx": 91 }, { "icon": { @@ -2221,6 +2481,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-excel-o" ], @@ -2229,15 +2491,15 @@ }, "attrs": [], "properties": { - "name": "file-excel", - "id": 92, - "order": 661, + "name": "file-excel-o", + "id": 91, + "order": 1809, "prevSize": 32, "code": 61891 }, "setIdx": 0, - "setId": 0, - "iconIdx": 90 + "setId": 2, + "iconIdx": 92 }, { "icon": { @@ -2246,6 +2508,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-image-o", "file-photo-o", @@ -2256,15 +2520,42 @@ }, "attrs": [], "properties": { - "name": "file-image", - "id": 93, - "order": 662, + "name": "file-image-o", + "id": 92, + "order": 1810, "prevSize": 32, "code": 61893 }, "setIdx": 0, - "setId": 0, - "iconIdx": 91 + "setId": 2, + "iconIdx": 93 + }, + { + "icon": { + "paths": [ + "M838.857 217.143c21.143 21.143 38.857 63.429 38.857 93.714v658.286c0 30.286-24.571 54.857-54.857 54.857h-768c-30.286 0-54.857-24.571-54.857-54.857v-914.286c0-30.286 24.571-54.857 54.857-54.857h512c30.286 0 72.571 17.714 93.714 38.857zM585.143 77.714v214.857h214.857c-3.429-9.714-8.571-19.429-12.571-23.429l-178.857-178.857c-4-4-13.714-9.143-23.429-12.571zM804.571 950.857v-585.143h-237.714c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-438.857v877.714h731.429z" + ], + "width": 877.7142857142857, + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "file-o" + ], + "defaultCode": 61462, + "grid": 16 + }, + "attrs": [], + "properties": { + "name": "file-o", + "id": 93, + "order": 1811, + "prevSize": 32, + "code": 61462 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 94 }, { "icon": { @@ -2273,6 +2564,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-pdf-o" ], @@ -2281,15 +2574,15 @@ }, "attrs": [], "properties": { - "name": "file-pdf", - "id": 95, - "order": 664, + "name": "file-pdf-o", + "id": 94, + "order": 1812, "prevSize": 32, "code": 61889 }, "setIdx": 0, - "setId": 0, - "iconIdx": 92 + "setId": 2, + "iconIdx": 95 }, { "icon": { @@ -2298,6 +2591,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-powerpoint-o" ], @@ -2306,15 +2601,15 @@ }, "attrs": [], "properties": { - "name": "file-powerpoint", - "id": 96, - "order": 665, + "name": "file-powerpoint-o", + "id": 95, + "order": 1813, "prevSize": 32, "code": 61892 }, "setIdx": 0, - "setId": 0, - "iconIdx": 93 + "setId": 2, + "iconIdx": 96 }, { "icon": { @@ -2323,6 +2618,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-text-o" ], @@ -2331,15 +2628,15 @@ }, "attrs": [], "properties": { - "name": "file-text", - "id": 97, - "order": 666, + "name": "file-text-o", + "id": 96, + "order": 1814, "prevSize": 32, "code": 61686 }, "setIdx": 0, - "setId": 0, - "iconIdx": 94 + "setId": 2, + "iconIdx": 97 }, { "icon": { @@ -2348,6 +2645,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-movie-o", "file-video-o" @@ -2357,15 +2656,15 @@ }, "attrs": [], "properties": { - "name": "file-video", - "id": 98, - "order": 667, + "name": "file-video-o", + "id": 97, + "order": 1815, "prevSize": 32, "code": 61896 }, "setIdx": 0, - "setId": 0, - "iconIdx": 95 + "setId": 2, + "iconIdx": 98 }, { "icon": { @@ -2374,6 +2673,8 @@ ], "width": 877.7142857142857, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "file-word-o" ], @@ -2382,15 +2683,15 @@ }, "attrs": [], "properties": { - "name": "file-word", - "id": 99, - "order": 668, + "name": "file-word-o", + "id": 98, + "order": 1816, "prevSize": 32, "code": 61890 }, "setIdx": 0, - "setId": 0, - "iconIdx": 96 + "setId": 2, + "iconIdx": 99 }, { "icon": { @@ -2398,6 +2699,8 @@ "M426.667 768h170.667v-85.333h-170.667v85.333zM128 256v85.333h768v-85.333h-768zM256 554.667h512v-85.333h-512v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "filter" ], @@ -2406,15 +2709,15 @@ }, "attrs": [], "properties": { - "order": 669, - "id": 100, + "order": 1817, + "id": 99, "name": "filter", "prevSize": 32, "code": 59671 }, "setIdx": 0, - "setId": 0, - "iconIdx": 97 + "setId": 2, + "iconIdx": 100 }, { "icon": { @@ -2422,6 +2725,8 @@ "M614.4 256l-17.067-85.333h-384v725.333h85.333v-298.667h238.933l17.067 85.333h298.667v-426.667h-238.933z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "flag" ], @@ -2430,15 +2735,15 @@ }, "attrs": [], "properties": { - "order": 670, - "id": 101, + "order": 1818, + "id": 100, "name": "flag", "prevSize": 32, "code": 59757 }, "setIdx": 0, - "setId": 0, - "iconIdx": 98 + "setId": 2, + "iconIdx": 101 }, { "icon": { @@ -2448,6 +2753,8 @@ "M469.333 256h85.333v512h-85.333v-512z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "flip" ], @@ -2456,15 +2763,15 @@ }, "attrs": [], "properties": { - "order": 671, - "id": 102, + "order": 1819, + "id": 101, "name": "flip", "prevSize": 32, "code": 59758 }, "setIdx": 0, - "setId": 0, - "iconIdx": 99 + "setId": 2, + "iconIdx": 102 }, { "icon": { @@ -2472,6 +2779,8 @@ "M426.667 170.667h-256c-46.933 0-84.907 38.4-84.907 85.333l-0.427 512c0 46.933 38.4 85.333 85.333 85.333h682.667c46.933 0 85.333-38.4 85.333-85.333v-426.667c0-46.933-38.4-85.333-85.333-85.333h-341.333l-85.333-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "folder" ], @@ -2480,94 +2789,54 @@ }, "attrs": [], "properties": { - "order": 672, - "id": 103, + "order": 1820, + "id": 102, "name": "folder", "prevSize": 32, "code": 59873 }, "setIdx": 0, - "setId": 0, - "iconIdx": 100 + "setId": 2, + "iconIdx": 103 }, { "icon": { "paths": [ - "M791.275 93.091h-558.547c-12.345 0-24.184 4.904-32.913 13.633s-13.633 20.568-13.633 32.913v744.728c0 12.343 4.904 24.183 13.633 32.913s20.568 13.632 32.913 13.632h558.547c12.343 0 24.183-4.902 32.913-13.632 8.725-8.73 13.632-20.57 13.632-32.913v-744.728c0-12.344-4.907-24.183-13.632-32.913-8.73-8.729-20.57-13.633-32.913-13.633zM744.73 837.82h-465.456v-651.638h465.456v651.638zM651.635 279.273h-279.271v93.091h279.271v-93.091zM651.635 651.635h-279.271v93.094h279.271v-93.094zM651.635 465.455h-279.271v93.090h279.271v-93.090z" + "M533.333 896v-75.733l230.4-230.4 75.733 75.733-230.4 230.4h-75.733zM149.333 672v-64h320v64h-320zM885.333 619.733l-75.733-75.733 30.933-30.933c5.687-5.687 13.154-8.533 22.4-8.533s16.713 2.846 22.4 8.533l30.933 30.933c5.687 5.687 8.533 13.154 8.533 22.4s-2.846 16.713-8.533 22.4l-30.933 30.933zM149.333 496v-64h501.333v64h-501.333zM149.333 320v-64h501.333v64h-501.333z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "form" ], "defaultCode": 59672, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 673, - "id": 104, + "order": 1821, + "id": 103, "name": "form", "prevSize": 32, "code": 59672 }, "setIdx": 0, - "setId": 0, - "iconIdx": 101 + "setId": 2, + "iconIdx": 104 }, { "icon": { "paths": [ - "M576 661.333h-149.333v-128h149.333c16.973 0 33.254 6.741 45.257 18.743s18.743 28.284 18.743 45.257c0 16.973-6.741 33.254-18.743 45.257s-28.284 18.743-45.257 18.743zM426.667 277.333h128c16.973 0 33.254 6.743 45.257 18.745s18.743 28.281 18.743 45.255c0 16.974-6.741 33.253-18.743 45.255s-28.284 18.745-45.257 18.745h-128v-128zM665.6 460.373c41.387-29.013 70.4-76.373 70.4-119.040 0-96.427-74.667-170.667-170.667-170.667h-266.667v597.333h300.373c89.6 0 158.293-72.533 158.293-161.707 0-64.853-36.693-120.32-91.733-145.92z" - ], - "attrs": [], - "tags": [ - "mdi-format-bold" - ], - "defaultCode": 59683, - "grid": 16 - }, - "attrs": [], - "properties": { - "order": 717, - "id": 148, - "name": "format-bold", - "prevSize": 32, - "code": 59683 - }, - "setIdx": 0, - "setId": 0, - "iconIdx": 102 - }, - { - "icon": { - "paths": [ - "M426.667 170.667v128h94.293l-145.92 341.333h-119.040v128h341.333v-128h-94.293l145.92-341.333h119.040v-128h-341.333z" - ], - "attrs": [], - "tags": [ - "mdi-format-italic" - ], - "defaultCode": 59684, - "grid": 16 - }, - "attrs": [], - "properties": { - "order": 718, - "id": 149, - "name": "format-italic", - "prevSize": 32, - "code": 59684 - }, - "setIdx": 0, - "setId": 0, - "iconIdx": 103 - }, - { - "icon": { - "paths": [ - "M170.667 469.333h519.253l-238.507-238.507 60.587-60.16 341.333 341.333-341.333 341.333-60.16-60.16 238.080-238.507h-519.253v-85.333z" + "M170.667 469.333h519.253l-238.507-238.507 60.587-60.16 341.333 341.333-341.333 341.333-60.16-60.16 238.080-238.507h-519.253v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "forward" ], @@ -2576,15 +2845,15 @@ }, "attrs": [], "properties": { - "order": 674, - "id": 105, + "order": 1822, + "id": 104, "name": "forward", "prevSize": 32, "code": 59760 }, "setIdx": 0, - "setId": 0, - "iconIdx": 104 + "setId": 2, + "iconIdx": 105 }, { "icon": { @@ -2592,6 +2861,8 @@ "M298.667 597.333h-85.333v213.333h213.333v-85.333h-128v-128zM213.333 426.667h85.333v-128h128v-85.333h-213.333v213.333zM725.333 725.333h-128v85.333h213.333v-213.333h-85.333v128zM597.333 213.333v85.333h128v128h85.333v-213.333h-213.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "fullscreen" ], @@ -2600,15 +2871,15 @@ }, "attrs": [], "properties": { - "order": 675, - "id": 106, + "order": 1823, + "id": 105, "name": "fullscreen", "prevSize": 32, "code": 59762 }, "setIdx": 0, - "setId": 0, - "iconIdx": 105 + "setId": 2, + "iconIdx": 106 }, { "icon": { @@ -2616,6 +2887,8 @@ "M213.333 682.667h128v128h85.333v-213.333h-213.333v85.333zM341.333 341.333h-128v85.333h213.333v-213.333h-85.333v128zM597.333 810.667h85.333v-128h128v-85.333h-213.333v213.333zM682.667 341.333v-128h-85.333v213.333h213.333v-85.333h-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "fullscreen-exit" ], @@ -2624,15 +2897,15 @@ }, "attrs": [], "properties": { - "order": 676, - "id": 107, + "order": 1824, + "id": 106, "name": "fullscreen-exit", "prevSize": 32, "code": 59761 }, "setIdx": 0, - "setId": 0, - "iconIdx": 106 + "setId": 2, + "iconIdx": 107 }, { "icon": { @@ -2641,6 +2914,8 @@ "M776.070 587.071l-63.101 63.101-63.101-63.101-34.352 34.352 63.101 63.101-63.101 63.103 34.352 34.352 63.101-63.103 63.101 63.103 34.354-34.352-63.103-63.103 63.103-63.101-34.354-34.352zM712.969 440.889c-134.73 0-243.635 108.905-243.635 243.635s108.905 243.635 243.635 243.635 243.635-108.904 243.635-243.635c0-134.73-108.905-243.635-243.635-243.635zM712.969 879.433c-107.443 0-194.908-87.465-194.908-194.908s87.465-194.908 194.908-194.908c107.443 0 194.908 87.465 194.908 194.908s-87.465 194.908-194.908 194.908z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "funnel" ], @@ -2649,8 +2924,8 @@ }, "attrs": [], "properties": { - "order": 677, - "id": 108, + "order": 1825, + "id": 107, "name": "funnel", "prevSize": 32, "codes": [ @@ -2659,8 +2934,8 @@ "code": 59673 }, "setIdx": 0, - "setId": 0, - "iconIdx": 107 + "setId": 2, + "iconIdx": 108 }, { "icon": { @@ -2668,6 +2943,8 @@ "M511.573 85.333c-235.52 0-426.24 191.147-426.24 426.667s190.72 426.667 426.24 426.667c235.947 0 427.093-191.147 427.093-426.667s-191.147-426.667-427.093-426.667zM807.253 341.333h-125.867c-13.653-53.333-33.28-104.533-58.88-151.893 78.507 26.88 143.787 81.493 184.747 151.893zM512 172.373c35.413 51.2 63.147 107.947 81.493 168.96h-162.987c18.347-61.013 46.080-117.76 81.493-168.96zM181.76 597.333c-6.827-27.307-11.093-55.893-11.093-85.333s4.267-58.027 11.093-85.333h144.213c-3.413 28.16-5.973 56.32-5.973 85.333s2.56 57.173 5.973 85.333h-144.213zM216.747 682.667h125.867c13.653 53.333 33.28 104.533 58.88 151.893-78.507-26.88-143.787-81.067-184.747-151.893zM342.613 341.333h-125.867c40.96-70.827 106.24-125.013 184.747-151.893-25.6 47.36-45.227 98.56-58.88 151.893zM512 851.627c-35.413-51.2-63.147-107.947-81.493-168.96h162.987c-18.347 61.013-46.080 117.76-81.493 168.96zM611.84 597.333h-199.68c-3.84-28.16-6.827-56.32-6.827-85.333s2.987-57.6 6.827-85.333h199.68c3.84 27.733 6.827 56.32 6.827 85.333s-2.987 57.173-6.827 85.333zM622.507 834.56c25.6-47.36 45.227-98.56 58.88-151.893h125.867c-40.96 70.4-106.24 125.013-184.747 151.893zM698.027 597.333c3.413-28.16 5.973-56.32 5.973-85.333s-2.56-57.173-5.973-85.333h144.213c6.827 27.307 11.093 55.893 11.093 85.333s-4.267 58.027-11.093 85.333h-144.213z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "globe" ], @@ -2676,15 +2953,15 @@ }, "attrs": [], "properties": { - "order": 678, - "id": 109, + "order": 1826, + "id": 108, "name": "globe", "prevSize": 32, "code": 59874 }, "setIdx": 0, - "setId": 0, - "iconIdx": 108 + "setId": 2, + "iconIdx": 109 }, { "icon": { @@ -2696,6 +2973,8 @@ "M501.035 425.557c-11.406 0.035-21.49 5.659-27.663 14.276l-0.070 0.103c-4.48 5.632-6.997 10.667-9.387 15.701-4.608 10.027-7.851 20.139-8.96 23.467v0.128l-103.168 301.44c-1.8 4.884-2.841 10.525-2.841 16.409 0 10.58 3.366 20.373 9.085 28.368l-0.1-0.148v0.085c9.173 12.971 24.235 20.48 40.107 20.48 21.282-0.061 39.355-13.733 45.976-32.767l0.104-0.343v-0.128l24.832-75.435h83.371l25.685 75.776v0.085c6.897 19.29 25.011 32.846 46.292 32.853l0.982 0c0.277 0.006 0.603 0.009 0.93 0.009 26.957 0 48.811-21.853 48.811-48.811 0-5.894-1.045-11.544-2.959-16.775l0.109 0.339-102.4-301.355c-1.28-3.584-4.309-13.653-8.96-23.68-2.629-6.026-5.773-11.223-9.5-15.936l0.114 0.149c-6.232-8.695-16.306-14.293-27.687-14.293-0.016 0-0.032 0-0.049 0l0.003-0zM512.384 479.445c0.853 2.005 1.621 4.139 2.432 6.4h-4.779c0.853-2.261 1.493-4.395 2.347-6.443zM510.592 606.080l14.549 42.283h-28.928zM574.891 661.461l15.787 46.421c-7.552-10.027-16.085-18.859-28.587-20.992 2.816-2.475 7.509-1.877 9.728-4.992 4.267-5.931 1.749-13.483 3.072-20.48zM447.445 667.776c1.536 4.693-0.768 10.155 2.133 14.251 2.432 3.2 7.253 2.688 10.24 5.205-11.051 1.707-17.792 10.069-25.173 18.091z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "glossary" ], @@ -2703,15 +2982,15 @@ }, "attrs": [], "properties": { - "order": 679, - "id": 110, + "order": 1827, + "id": 109, "name": "glossary", "prevSize": 32, "code": 59649 }, "setIdx": 0, - "setId": 0, - "iconIdx": 109 + "setId": 2, + "iconIdx": 110 }, { "icon": { @@ -2719,6 +2998,8 @@ "M170.667 341.333h170.667v-170.667h-170.667v170.667zM426.667 853.333h170.667v-170.667h-170.667v170.667zM170.667 853.333h170.667v-170.667h-170.667v170.667zM170.667 597.333h170.667v-170.667h-170.667v170.667zM426.667 597.333h170.667v-170.667h-170.667v170.667zM682.667 170.667v170.667h170.667v-170.667h-170.667zM426.667 341.333h170.667v-170.667h-170.667v170.667zM682.667 597.333h170.667v-170.667h-170.667v170.667zM682.667 853.333h170.667v-170.667h-170.667v170.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "grid" ], @@ -2727,15 +3008,15 @@ }, "attrs": [], "properties": { - "order": 680, - "id": 111, + "order": 1828, + "id": 110, "name": "grid", "prevSize": 32, "code": 59763 }, "setIdx": 0, - "setId": 0, - "iconIdx": 110 + "setId": 2, + "iconIdx": 111 }, { "icon": { @@ -2743,6 +3024,8 @@ "M464 632v-215.46c0-26.505-21.495-48-48-48h-72c-53.025 0-96 42.975-96 96.002v119.458c0 53.026 42.975 96 96 96h72c26.505 0 48-21.495 48-48zM392 608h-48c-13.23 0-24-10.769-24-24v-119.458c0-13.231 10.77-24 24-24h48v167.458zM512 128c-214.23 0-377.13 178.245-384 384v24c0 13.261 10.74 24 24 24h24c13.26 0 24-10.739 24-24v-24c0-172.035 139.965-312 312-312 172.036 0 312 139.965 312 312h-0.179c0.119 3.644 0.179 248.58 0.179 248.58 0 35.025-28.395 63.42-63.42 63.42h-152.58c0-39.765-32.235-72-72-72h-48c-39.765 0-72 32.235-72 72s32.235 72 72 72h272.58c74.79 0 135.42-60.629 135.42-135.42v-248.58c-6.869-205.755-169.771-384-384-384zM680 680c53.026 0 96-42.974 96-96v-119.458c0-53.027-42.974-96.002-96-96.002h-72c-26.505 0-48 21.495-48 48v215.46c0 26.505 21.495 48 48 48h72zM632 440.542h48c13.231 0 24 10.769 24 24v119.458c0 13.231-10.769 24-24 24h-48v-167.458z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "headset" ], @@ -2751,15 +3034,15 @@ }, "attrs": [], "properties": { - "order": 681, - "id": 112, + "order": 1829, + "id": 111, "name": "headset", "prevSize": 32, "code": 59875 }, "setIdx": 0, - "setId": 0, - "iconIdx": 111 + "setId": 2, + "iconIdx": 112 }, { "icon": { @@ -2767,6 +3050,8 @@ "M554.656 128c-212.053 0-384 171.947-384 384h-128l165.974 165.971 2.986 5.978 172.374-171.949h-128c0-165.12 133.546-298.667 298.666-298.667s298.669 133.547 298.669 298.667c0 165.12-133.549 298.669-298.669 298.669-82.346 0-157.013-33.709-210.773-87.898l-60.587 60.589c69.547 69.549 165.12 112.64 271.36 112.64 212.051 0 384-171.949 384-384 0-212.053-171.949-384-384-384zM511.99 341.333v213.334l182.615 108.373 30.72-51.627-149.335-88.746v-181.334h-64z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "history" ], @@ -2775,15 +3060,15 @@ }, "attrs": [], "properties": { - "order": 682, - "id": 113, + "order": 1830, + "id": 112, "name": "history", "prevSize": 32, "code": 59674 }, "setIdx": 0, - "setId": 0, - "iconIdx": 112 + "setId": 2, + "iconIdx": 113 }, { "icon": { @@ -2791,6 +3076,8 @@ "M426.667 853.333v-256h170.667v256h213.333v-341.333h128l-426.667-384-426.667 384h128v341.333h213.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "home" ], @@ -2799,15 +3086,15 @@ }, "attrs": [], "properties": { - "order": 683, - "id": 114, + "order": 1831, + "id": 113, "name": "home", "prevSize": 32, "code": 59765 }, "setIdx": 0, - "setId": 0, - "iconIdx": 113 + "setId": 2, + "iconIdx": 114 }, { "icon": { @@ -2819,6 +3106,8 @@ "M684.201 511.986c0-65.435-28.536-124.476-73.8-164.82v329.149c45.264-39.852 73.8-98.892 73.8-164.329z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "horn" ], @@ -2827,15 +3116,15 @@ }, "attrs": [], "properties": { - "order": 684, - "id": 115, + "order": 1832, + "id": 114, "name": "horn", "prevSize": 32, "code": 59675 }, "setIdx": 0, - "setId": 0, - "iconIdx": 114 + "setId": 2, + "iconIdx": 115 }, { "icon": { @@ -2843,6 +3132,8 @@ "M768 938.667l-0.427-256-170.24-170.667 170.24-171.093 0.427-255.573h-512v256l170.667 170.667-170.667 170.24v256.427h512zM341.333 320v-149.333h341.333v149.333l-170.667 170.667-170.667-170.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "hourglass" ], @@ -2851,15 +3142,15 @@ }, "attrs": [], "properties": { - "order": 685, - "id": 116, + "order": 1833, + "id": 115, "name": "hourglass", "prevSize": 32, "code": 59876 }, "setIdx": 0, - "setId": 0, - "iconIdx": 115 + "setId": 2, + "iconIdx": 116 }, { "icon": { @@ -2867,6 +3158,8 @@ "M565.333 714.24c0 29.44-22.613 53.76-53.333 53.76-29.867 0-53.76-23.893-53.76-53.76 0-30.293 23.893-53.333 53.76-53.333 30.293 0 53.333 23.467 53.333 53.333zM511.573 256c-75.52 0-127.147 49.067-146.347 106.24l69.973 29.44c9.387-28.587 31.573-63.147 76.8-63.147 69.12 0 82.773 64.853 58.453 99.413-23.040 32.853-62.72 55.040-83.627 92.16-16.64 29.44-13.227 63.573-13.227 84.48h77.653c0-39.68 2.987-47.787 9.387-60.16 16.64-30.72 47.36-45.227 79.787-92.587 29.013-42.667 17.92-100.693-0.853-131.413-21.76-35.84-64.853-64.427-128-64.427zM810.667 213.333h-597.333v597.333h597.333v-597.333zM810.667 128c46.933 0 85.333 38.4 85.333 85.333v597.333c0 46.933-38.4 85.333-85.333 85.333h-597.333c-46.933 0-85.333-38.4-85.333-85.333v-597.333c0-46.933 38.4-85.333 85.333-85.333h597.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "how do I" ], @@ -2875,15 +3168,119 @@ }, "attrs": [], "properties": { - "order": 686, - "id": 117, + "order": 1834, + "id": 116, "name": "how-do-I", "prevSize": 32, "code": 59676 }, "setIdx": 0, - "setId": 0, - "iconIdx": 116 + "setId": 2, + "iconIdx": 117 + }, + { + "icon": { + "paths": [ + "M512 725.333c141.227 0 256-114.773 256-256v-341.333h-106.667v341.333c0 82.347-66.987 149.333-149.333 149.333s-149.333-66.987-149.333-149.333v-341.333h-106.667v341.333c0 141.227 114.773 256 256 256zM213.333 810.667v85.333h597.333v-85.333h-597.333z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "ic-baseline-format-underlined" + ], + "defaultCode": 59676, + "grid": 16 + }, + "attrs": [], + "properties": { + "order": 1835, + "id": 117, + "name": "ic-baseline-format-underlined", + "prevSize": 32, + "code": 59677 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 118 + }, + { + "icon": { + "paths": [ + "M292.267 302.080c0-115.627 110.933-174.080 229.973-174.080 69.973 0 128 20.907 166.4 54.613 32.853 27.733 62.293 73.813 62.293 138.24h-128.427c0-13.227-2.133-25.173-6.4-36.267-12.373-36.693-51.2-54.613-96-54.613-79.36 0-99.84 43.52-99.84 72.533 0 20.48 10.667 37.547 31.573 51.627 16.213 10.667 32.853 20.48 60.16 29.867h-196.693c-8.96-14.507-23.040-37.973-23.040-81.92zM896 512v-85.333h-768v85.333h410.453c49.067 19.2 83.627 32 83.627 84.053 0 42.667-34.56 71.253-97.28 71.253-65.707 0-125.013-23.040-125.013-107.093h-126.72c0 23.467 3.413 48.213 10.24 67.413 34.56 97.707 140.373 140.8 241.92 140.8 96.853 0 226.133-37.973 226.133-172.8 0-12.8-0.427-49.493-20.48-82.773h165.12v-0.853z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "ic-baseline-strikethrough-s" + ], + "defaultCode": 59677, + "grid": 16 + }, + "attrs": [], + "properties": { + "order": 1836, + "id": 118, + "name": "ic-baseline-strikethrough-s", + "prevSize": 32, + "code": 59678 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 119 + }, + { + "icon": { + "paths": [ + "M170.667 448c-35.413 0-64 28.587-64 64s28.587 64 64 64c35.413 0 64-28.587 64-64s-28.587-64-64-64zM170.667 192c-35.413 0-64 28.587-64 64s28.587 64 64 64c35.413 0 64-28.587 64-64s-28.587-64-64-64zM170.667 704c-35.413 0-64 29.013-64 64s29.013 64 64 64c34.987 0 64-29.013 64-64s-28.587-64-64-64zM341.333 810.667h512c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-512c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM341.333 554.667h512c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-512c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM298.667 256c0 23.467 19.2 42.667 42.667 42.667h512c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-512c-23.467 0-42.667 19.2-42.667 42.667z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "ic-round-format-list-bulleted" + ], + "defaultCode": 59678, + "grid": 16 + }, + "attrs": [], + "properties": { + "order": 1837, + "id": 119, + "name": "ic-round-format-list-bulleted", + "prevSize": 32, + "code": 59679 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 120 + }, + { + "icon": { + "paths": [ + "M85.333 725.333h85.333v21.333h-42.667v42.667h42.667v21.333h-85.333v42.667h128v-170.667h-128v42.667zM128 341.333h42.667v-170.667h-85.333v42.667h42.667v128zM85.333 469.333h76.8l-76.8 89.6v38.4h128v-42.667h-76.8l76.8-89.6v-38.4h-128v42.667zM298.667 213.333v85.333h597.333v-85.333h-597.333zM298.667 810.667h597.333v-85.333h-597.333v85.333zM298.667 554.667h597.333v-85.333h-597.333v85.333z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "ic-sharp-format-list-numbered" + ], + "defaultCode": 59679, + "grid": 16 + }, + "attrs": [], + "properties": { + "order": 1838, + "id": 120, + "name": "ic-sharp-format-list-numbered", + "prevSize": 32, + "code": 59680 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 121 }, { "icon": { @@ -2891,6 +3288,8 @@ "M896 810.667v-597.333c0-46.933-38.4-85.333-85.333-85.333h-597.333c-46.933 0-85.333 38.4-85.333 85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333zM362.667 576l106.667 128.427 149.333-192.427 192 256h-597.333l149.333-192z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "image" ], @@ -2899,15 +3298,15 @@ }, "attrs": [], "properties": { - "order": 691, - "id": 122, + "order": 1839, + "id": 121, "name": "image", "prevSize": 32, "code": 59766 }, "setIdx": 0, - "setId": 0, - "iconIdx": 117 + "setId": 2, + "iconIdx": 122 }, { "icon": { @@ -2915,6 +3314,8 @@ "M810.667 512v298.667h-597.333v-298.667h-85.333v298.667c0 46.933 38.4 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-298.667h-85.333zM554.667 540.587l110.507-110.080 60.16 60.16-213.333 213.333-213.333-213.333 60.16-60.16 110.507 110.080v-412.587h85.333v412.587z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "import" ], @@ -2923,15 +3324,15 @@ }, "attrs": [], "properties": { - "order": 692, - "id": 123, + "order": 1840, + "id": 122, "name": "import", "prevSize": 32, "code": 59877 }, "setIdx": 0, - "setId": 0, - "iconIdx": 118 + "setId": 2, + "iconIdx": 123 }, { "icon": { @@ -2939,6 +3340,8 @@ "M810.667 128h-597.76c-47.36 0-84.48 37.973-84.48 85.333l-0.427 597.333c0 46.933 37.547 85.333 84.907 85.333h597.76c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-47.36-38.4-85.333-85.333-85.333zM810.667 640h-170.667c0 70.827-57.6 128-128 128s-128-57.173-128-128h-171.093v-426.667h597.76v426.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "inbox" ], @@ -2947,15 +3350,44 @@ }, "attrs": [], "properties": { - "order": 693, - "id": 124, + "order": 1841, + "id": 123, "name": "inbox", "prevSize": 32, "code": 59878 }, "setIdx": 0, - "setId": 0, - "iconIdx": 119 + "setId": 2, + "iconIdx": 124 + }, + { + "icon": { + "paths": [ + "M554.426 362.426c-23.432-23.432-61.42-23.432-84.852 0l-239.148 239.148c-37.797 37.798-11.028 102.426 42.426 102.426h478.296c53.454 0 80.224-64.628 42.426-102.426l-239.148-239.148z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "increase" + ], + "grid": 16 + }, + "attrs": [ + {} + ], + "properties": { + "order": 1842, + "id": 124, + "name": "increase", + "prevSize": 32, + "code": 59815 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 125 }, { "icon": { @@ -2963,6 +3395,8 @@ "M512 938.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667zM469.333 298.667h85.333v256h-85.333v-256zM469.333 640h85.333v85.333h-85.333v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "indicator-alert" ], @@ -2971,15 +3405,15 @@ }, "attrs": [], "properties": { - "order": 695, - "id": 126, + "order": 1843, + "id": 125, "name": "indicator-alert", "prevSize": 32, "code": 59767 }, "setIdx": 0, - "setId": 0, - "iconIdx": 120 + "setId": 2, + "iconIdx": 126 }, { "icon": { @@ -2987,6 +3421,8 @@ "M512 85.333c-235.947 0-426.667 190.72-426.667 426.667s190.72 426.667 426.667 426.667c235.947 0 426.667-190.72 426.667-426.667s-190.72-426.667-426.667-426.667zM725.333 665.173l-60.16 60.16-153.173-153.173-153.173 153.173-60.16-60.16 153.173-153.173-153.173-153.173 60.16-60.16 153.173 153.173 153.173-153.173 60.16 60.16-153.173 153.173 153.173 153.173z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "indicator-cancel" ], @@ -2995,15 +3431,15 @@ }, "attrs": [], "properties": { - "order": 696, - "id": 127, + "order": 1844, + "id": 126, "name": "indicator-cancel", "prevSize": 32, "code": 59768 }, "setIdx": 0, - "setId": 0, - "iconIdx": 121 + "setId": 2, + "iconIdx": 127 }, { "icon": { @@ -3011,6 +3447,8 @@ "M512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM426.667 725.333l-213.333-213.333 60.16-60.16 153.173 152.747 323.84-323.84 60.16 60.587-384 384z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "indicator-check" ], @@ -3019,15 +3457,15 @@ }, "attrs": [], "properties": { - "order": 697, - "id": 128, + "order": 1845, + "id": 127, "name": "indicator-check", "prevSize": 32, "code": 59769 }, "setIdx": 0, - "setId": 0, - "iconIdx": 122 + "setId": 2, + "iconIdx": 128 }, { "icon": { @@ -3035,6 +3473,8 @@ "M512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM554.667 810.667h-85.333v-85.333h85.333v85.333zM642.987 480l-38.4 39.253c-30.72 31.147-49.92 56.747-49.92 120.747h-85.333v-21.333c0-46.933 19.2-89.6 49.92-120.747l52.907-53.76c15.787-15.36 25.173-36.693 25.173-60.16 0-46.933-38.4-85.333-85.333-85.333s-85.333 38.4-85.333 85.333h-85.333c0-94.293 76.373-170.667 170.667-170.667s170.667 76.373 170.667 170.667c0 37.547-15.36 71.68-39.68 96z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "indicator-help" ], @@ -3043,15 +3483,15 @@ }, "attrs": [], "properties": { - "order": 698, - "id": 129, + "order": 1846, + "id": 128, "name": "indicator-help", "prevSize": 32, "code": 59770 }, "setIdx": 0, - "setId": 0, - "iconIdx": 123 + "setId": 2, + "iconIdx": 129 }, { "icon": { @@ -3059,6 +3499,8 @@ "M512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM554.667 725.333h-85.333v-256h85.333v256zM554.667 384h-85.333v-85.333h85.333v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "indicator-info" ], @@ -3067,15 +3509,15 @@ }, "attrs": [], "properties": { - "order": 699, - "id": 130, + "order": 1847, + "id": 129, "name": "indicator-info", "prevSize": 32, "code": 59771 }, "setIdx": 0, - "setId": 0, - "iconIdx": 124 + "setId": 2, + "iconIdx": 130 }, { "icon": { @@ -3083,6 +3525,8 @@ "M469.333 298.667h85.333v85.333h-85.333v-85.333zM469.333 469.333h85.333v256h-85.333v-256zM512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM512 853.333c-188.16 0-341.333-153.173-341.333-341.333s153.173-341.333 341.333-341.333c188.16 0 341.333 153.173 341.333 341.333s-153.173 341.333-341.333 341.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "info" ], @@ -3091,15 +3535,15 @@ }, "attrs": [], "properties": { - "order": 700, - "id": 131, + "order": 1848, + "id": 130, "name": "info", "prevSize": 32, "code": 59681 }, "setIdx": 0, - "setId": 0, - "iconIdx": 125 + "setId": 2, + "iconIdx": 131 }, { "icon": { @@ -3107,6 +3551,8 @@ "M853.333 213.333h-682.667c-46.933 0-84.907 38.4-84.907 85.333l-0.427 426.667c0 46.933 38.4 85.333 85.333 85.333h682.667c46.933 0 85.333-38.4 85.333-85.333v-426.667c0-46.933-38.4-85.333-85.333-85.333zM469.333 341.333h85.333v85.333h-85.333v-85.333zM469.333 469.333h85.333v85.333h-85.333v-85.333zM341.333 341.333h85.333v85.333h-85.333v-85.333zM341.333 469.333h85.333v85.333h-85.333v-85.333zM298.667 554.667h-85.333v-85.333h85.333v85.333zM298.667 426.667h-85.333v-85.333h85.333v85.333zM682.667 725.333h-341.333v-85.333h341.333v85.333zM682.667 554.667h-85.333v-85.333h85.333v85.333zM682.667 426.667h-85.333v-85.333h85.333v85.333zM810.667 554.667h-85.333v-85.333h85.333v85.333zM810.667 426.667h-85.333v-85.333h85.333v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "keyboard" ], @@ -3115,15 +3561,15 @@ }, "attrs": [], "properties": { - "order": 701, - "id": 132, + "order": 1849, + "id": 131, "name": "keyboard", "prevSize": 32, "code": 59879 }, "setIdx": 0, - "setId": 0, - "iconIdx": 126 + "setId": 2, + "iconIdx": 132 }, { "icon": { @@ -3131,6 +3577,8 @@ "M810.667 810.667h-597.333v-597.333h298.667v-85.333h-298.667c-47.36 0-85.333 38.4-85.333 85.333v597.333c0 46.933 37.973 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-298.667h-85.333v298.667zM597.333 128v85.333h153.173l-419.413 419.413 60.16 60.16 419.413-419.413v153.173h85.333v-298.667h-298.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "launch" ], @@ -3139,15 +3587,15 @@ }, "attrs": [], "properties": { - "order": 702, - "id": 133, + "order": 1850, + "id": 132, "name": "launch", "prevSize": 32, "code": 59682 }, "setIdx": 0, - "setId": 0, - "iconIdx": 127 + "setId": 2, + "iconIdx": 133 }, { "icon": { @@ -3155,6 +3603,8 @@ "M384 896c0 21.333 17.067 42.667 42.667 42.667h170.667c25.6 0 42.667-21.333 42.667-42.667v-42.667h-256v42.667zM512 85.333c-166.4 0-298.667 132.267-298.667 298.667 0 102.4 51.2 192 128 243.2v98.133c0 21.333 17.067 42.667 42.667 42.667h256c25.6 0 42.667-21.333 42.667-42.667v-98.133c76.8-55.467 128-145.067 128-243.2 0-166.4-132.267-298.667-298.667-298.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "lightbulb" ], @@ -3163,15 +3613,15 @@ }, "attrs": [], "properties": { - "order": 703, - "id": 134, + "order": 1851, + "id": 133, "name": "lightbulb", "prevSize": 32, "code": 59880 }, "setIdx": 0, - "setId": 0, - "iconIdx": 128 + "setId": 2, + "iconIdx": 134 }, { "icon": { @@ -3179,6 +3629,8 @@ "M166.4 512c0-72.96 59.307-132.267 132.267-132.267h170.667v-81.067h-170.667c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333h170.667v-81.067h-170.667c-72.96 0-132.267-59.307-132.267-132.267zM341.333 554.667h341.333v-85.333h-341.333v85.333zM725.333 298.667h-170.667v81.067h170.667c72.96 0 132.267 59.307 132.267 132.267s-59.307 132.267-132.267 132.267h-170.667v81.067h170.667c117.76 0 213.333-95.573 213.333-213.333s-95.573-213.333-213.333-213.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "link" ], @@ -3187,15 +3639,15 @@ }, "attrs": [], "properties": { - "order": 704, - "id": 135, + "order": 1852, + "id": 134, "name": "link", "prevSize": 32, "code": 59773 }, "setIdx": 0, - "setId": 0, - "iconIdx": 129 + "setId": 2, + "iconIdx": 135 }, { "icon": { @@ -3203,6 +3655,8 @@ "M341.333 469.333h341.333v85.333h-341.333v-85.333zM857.6 512h81.067c0-117.759-95.573-213.332-213.333-213.332h-170.667v81.067h170.667c72.96 0 132.267 59.305 132.267 132.265zM166.4 512c0-72.96 59.307-132.265 132.267-132.265h170.667v-81.067h-170.667c-117.76 0-213.333 95.573-213.333 213.332s95.573 213.333 213.333 213.333h170.667v-81.067h-170.667c-72.96 0-132.267-59.307-132.267-132.267zM810.667 512h-85.333v128h-128v85.333h128v128h85.333v-128h128v-85.333h-128v-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "link-add" ], @@ -3211,15 +3665,15 @@ }, "attrs": [], "properties": { - "order": 705, - "id": 136, + "order": 1853, + "id": 135, "name": "link-add", "prevSize": 32, "code": 59772 }, "setIdx": 0, - "setId": 0, - "iconIdx": 130 + "setId": 2, + "iconIdx": 136 }, { "icon": { @@ -3227,6 +3681,8 @@ "M170.667 448c-35.413 0-64 28.587-64 64s28.587 64 64 64c35.413 0 64-28.587 64-64s-28.587-64-64-64zM170.667 192c-35.413 0-64 28.587-64 64s28.587 64 64 64c35.413 0 64-28.587 64-64s-28.587-64-64-64zM170.667 704c-35.413 0-64 29.013-64 64s29.013 64 64 64c34.987 0 64-29.013 64-64s-28.587-64-64-64zM298.667 810.667h597.333v-85.333h-597.333v85.333zM298.667 554.667h597.333v-85.333h-597.333v85.333zM298.667 213.333v85.333h597.333v-85.333h-597.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "list-bullet" ], @@ -3235,15 +3691,15 @@ }, "attrs": [], "properties": { - "order": 706, - "id": 137, + "order": 1854, + "id": 136, "name": "list-bullet", "prevSize": 32, "code": 59775 }, "setIdx": 0, - "setId": 0, - "iconIdx": 131 + "setId": 2, + "iconIdx": 137 }, { "icon": { @@ -3251,6 +3707,8 @@ "M213.333 128h597.333c46.933 0 85.333 38.4 85.333 85.333v597.333c0 46.933-38.4 85.333-85.333 85.333h-597.333c-46.933 0-85.333-38.4-85.333-85.333v-597.333c0-46.933 38.4-85.333 85.333-85.333zM213.333 213.333v597.333h597.333v-597.333h-597.333zM341.333 384c23.564 0 42.667-19.103 42.667-42.667s-19.103-42.667-42.667-42.667c-23.564 0-42.667 19.103-42.667 42.667s19.103 42.667 42.667 42.667zM512 384h170.667c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-170.667c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM512 554.667h170.667c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-170.667c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM512 725.333h170.667c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-170.667c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM384 512c0 23.565-19.103 42.667-42.667 42.667s-42.667-19.102-42.667-42.667c0-23.565 19.103-42.667 42.667-42.667s42.667 19.102 42.667 42.667zM341.333 725.333c23.564 0 42.667-19.102 42.667-42.667s-19.103-42.667-42.667-42.667c-23.564 0-42.667 19.102-42.667 42.667s19.103 42.667 42.667 42.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "list-bullet-contained" ], @@ -3259,39 +3717,15 @@ }, "attrs": [], "properties": { - "order": 707, - "id": 138, + "order": 1855, + "id": 137, "name": "list-bullet-contained", "prevSize": 32, "code": 59774 }, "setIdx": 0, - "setId": 0, - "iconIdx": 132 - }, - { - "icon": { - "paths": [ - "M170.667 448c-35.413 0-64 28.587-64 64s28.587 64 64 64c35.413 0 64-28.587 64-64s-28.587-64-64-64zM170.667 192c-35.413 0-64 28.587-64 64s28.587 64 64 64c35.413 0 64-28.587 64-64s-28.587-64-64-64zM170.667 704c-35.413 0-64 29.013-64 64s29.013 64 64 64c34.987 0 64-29.013 64-64s-28.587-64-64-64zM341.333 810.667h512c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-512c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM341.333 554.667h512c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-512c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM298.667 256c0 23.467 19.2 42.667 42.667 42.667h512c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-512c-23.467 0-42.667 19.2-42.667 42.667z" - ], - "attrs": [], - "tags": [ - "ic-round-format-list-bulleted" - ], - "defaultCode": 59678, - "grid": 16 - }, - "attrs": [], - "properties": { - "order": 689, - "id": 120, - "name": "list-bulleted", - "prevSize": 32, - "code": 59679 - }, - "setIdx": 0, - "setId": 0, - "iconIdx": 133 + "setId": 2, + "iconIdx": 138 }, { "icon": { @@ -3299,6 +3733,8 @@ "M128 554.667h85.333v-85.333h-85.333v85.333zM128 725.333h85.333v-85.333h-85.333v85.333zM128 384h85.333v-85.333h-85.333v85.333zM298.667 554.667h597.333v-85.333h-597.333v85.333zM298.667 725.333h597.333v-85.333h-597.333v85.333zM298.667 298.667v85.333h597.333v-85.333h-597.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "list-details" ], @@ -3307,15 +3743,15 @@ }, "attrs": [], "properties": { - "order": 708, - "id": 139, + "order": 1856, + "id": 138, "name": "list-details", "prevSize": 32, "code": 59776 }, "setIdx": 0, - "setId": 0, - "iconIdx": 134 + "setId": 2, + "iconIdx": 139 }, { "icon": { @@ -3323,6 +3759,8 @@ "M170.667 298.667h682.667v85.333h-682.667v-85.333zM170.667 554.667h682.667v-85.333h-682.667v85.333zM170.667 725.333h298.667v-85.333h-298.667v85.333zM170.667 896h298.667v-85.333h-298.667v85.333zM657.493 775.253l-60.16-60.587-60.16 60.16 120.32 121.173 195.84-195.413-60.587-60.587-135.253 135.253zM170.667 128v85.333h682.667v-85.333h-682.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "list-feedback" ], @@ -3331,63 +3769,41 @@ }, "attrs": [], "properties": { - "order": 709, - "id": 140, + "order": 1857, + "id": 139, "name": "list-feedback", "prevSize": 32, "code": 59777 }, "setIdx": 0, - "setId": 0, - "iconIdx": 135 - }, - { - "icon": { - "paths": [ - "M791.275 93.091h-558.547c-12.345 0-24.184 4.904-32.913 13.633s-13.633 20.568-13.633 32.913v744.728c0 12.343 4.904 24.183 13.633 32.913s20.568 13.632 32.913 13.632h558.547c12.343 0 24.183-4.902 32.913-13.632 8.725-8.73 13.632-20.57 13.632-32.913v-744.728c0-12.344-4.907-24.183-13.632-32.913-8.73-8.729-20.57-13.633-32.913-13.633zM744.73 837.82h-465.456v-651.638h465.456v651.638zM651.635 279.273h-279.271v93.091h279.271v-93.091zM651.635 651.635h-279.271v93.094h279.271v-93.094zM651.635 465.455h-279.271v93.090h279.271v-93.090z" - ], - "attrs": [], - "tags": [ - "list-form" - ], - "defaultCode": 59778, - "grid": 16 - }, - "attrs": [], - "properties": { - "order": 710, - "id": 141, - "name": "list-form", - "prevSize": 32, - "code": 59778 - }, - "setIdx": 0, - "setId": 0, - "iconIdx": 136 + "setId": 2, + "iconIdx": 140 }, { "icon": { "paths": [ - "M85.333 725.333h85.333v21.333h-42.667v42.667h42.667v21.333h-85.333v42.667h128v-170.667h-128v42.667zM128 341.333h42.667v-170.667h-85.333v42.667h42.667v128zM85.333 469.333h76.8l-76.8 89.6v38.4h128v-42.667h-76.8l76.8-89.6v-38.4h-128v42.667zM298.667 213.333v85.333h597.333v-85.333h-597.333zM298.667 810.667h597.333v-85.333h-597.333v85.333zM298.667 554.667h597.333v-85.333h-597.333v85.333z" + "M791.275 93.091h-558.547c-12.345 0-24.184 4.904-32.913 13.633s-13.633 20.568-13.633 32.913v744.728c0 12.343 4.904 24.183 13.633 32.913s20.568 13.632 32.913 13.632h558.547c12.343 0 24.183-4.902 32.913-13.632 8.725-8.73 13.632-20.57 13.632-32.913v-744.728c0-12.344-4.907-24.183-13.632-32.913-8.73-8.729-20.57-13.633-32.913-13.633zM744.73 837.82h-465.456v-651.638h465.456v651.638zM651.635 279.273h-279.271v93.091h279.271v-93.091zM651.635 651.635h-279.271v93.094h279.271v-93.094zM651.635 465.455h-279.271v93.090h279.271v-93.090z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ - "ic-sharp-format-list-numbered" + "list-form" ], - "defaultCode": 59679, + "defaultCode": 59778, "grid": 16 }, "attrs": [], "properties": { - "order": 690, - "id": 121, - "name": "list-numbered", + "order": 1858, + "id": 140, + "name": "list-form", "prevSize": 32, - "code": 59680 + "code": 59778 }, "setIdx": 0, - "setId": 0, - "iconIdx": 137 + "setId": 2, + "iconIdx": 141 }, { "icon": { @@ -3395,6 +3811,8 @@ "M938.667 298.666h-384v85.333h384v-85.333zM938.667 640h-384v85.333h384v-85.333zM236.373 469.333l-151.040-151.040 60.16-60.16 90.453 90.453 180.907-180.907 60.16 60.16-240.64 241.494zM236.373 810.667l-151.040-151.040 60.16-60.16 90.453 90.453 180.907-180.907 60.16 60.16-240.64 241.493z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "list-task" ], @@ -3403,15 +3821,15 @@ }, "attrs": [], "properties": { - "order": 711, - "id": 142, + "order": 1859, + "id": 141, "name": "list-task", "prevSize": 32, "code": 59779 }, "setIdx": 0, - "setId": 0, - "iconIdx": 138 + "setId": 2, + "iconIdx": 142 }, { "icon": { @@ -3419,6 +3837,8 @@ "M512 85.333c-179.2 0-341.333 137.387-341.333 349.867 0 141.653 113.92 309.333 341.333 503.467 227.413-194.133 341.333-361.813 341.333-503.467 0-212.48-162.133-349.867-341.333-349.867zM512 512c-46.933 0-85.333-38.4-85.333-85.333s38.4-85.333 85.333-85.333c46.933 0 85.333 38.4 85.333 85.333s-38.4 85.333-85.333 85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "location" ], @@ -3427,15 +3847,15 @@ }, "attrs": [], "properties": { - "order": 712, - "id": 143, + "order": 1860, + "id": 142, "name": "location", "prevSize": 32, "code": 59882 }, "setIdx": 0, - "setId": 0, - "iconIdx": 139 + "setId": 2, + "iconIdx": 143 }, { "icon": { @@ -3444,6 +3864,8 @@ "M961.707 122.88l-60.587-60.587-90.453 90.88-90.453-90.88-60.587 60.587 90.88 90.453-90.88 90.453 60.587 60.587 90.453-90.88 90.453 90.88 60.587-60.587-90.88-90.453 90.88-90.453z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "location-off" ], @@ -3452,15 +3874,15 @@ }, "attrs": [], "properties": { - "order": 713, - "id": 144, + "order": 1861, + "id": 143, "name": "location-off", "prevSize": 32, "code": 59881 }, "setIdx": 0, - "setId": 0, - "iconIdx": 140 + "setId": 2, + "iconIdx": 144 }, { "icon": { @@ -3468,6 +3890,8 @@ "M768 341.333h-42.667v-85.333c0-117.76-95.573-213.333-213.333-213.333s-213.333 95.573-213.333 213.333v85.333h-42.667c-46.933 0-85.333 38.4-85.333 85.333v426.667c0 46.933 38.4 85.333 85.333 85.333h512c46.933 0 85.333-38.4 85.333-85.333v-426.667c0-46.933-38.4-85.333-85.333-85.333zM512 725.333c-46.933 0-85.333-38.4-85.333-85.333s38.4-85.333 85.333-85.333c46.933 0 85.333 38.4 85.333 85.333s-38.4 85.333-85.333 85.333zM644.267 341.333h-264.533v-85.333c0-72.96 59.307-132.267 132.267-132.267s132.267 59.307 132.267 132.267v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "lock" ], @@ -3476,15 +3900,15 @@ }, "attrs": [], "properties": { - "order": 714, - "id": 145, + "order": 1862, + "id": 144, "name": "lock", "prevSize": 32, "code": 59781 }, "setIdx": 0, - "setId": 0, - "iconIdx": 141 + "setId": 2, + "iconIdx": 145 }, { "icon": { @@ -3492,6 +3916,8 @@ "M512 725.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM768 341.333h-42.667v-85.333c0-117.76-95.573-213.333-213.333-213.333s-213.333 95.573-213.333 213.333h81.067c0-72.96 59.307-132.267 132.267-132.267s132.267 59.307 132.267 132.267v85.333h-388.267c-46.933 0-85.333 38.4-85.333 85.333v426.667c0 46.933 38.4 85.333 85.333 85.333h512c46.933 0 85.333-38.4 85.333-85.333v-426.667c0-46.933-38.4-85.333-85.333-85.333zM768 853.333h-512v-426.667h512v426.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "lock-undo" ], @@ -3500,15 +3926,15 @@ }, "attrs": [], "properties": { - "order": 715, - "id": 146, + "order": 1863, + "id": 145, "name": "lock-undo", "prevSize": 32, "code": 59780 }, "setIdx": 0, - "setId": 0, - "iconIdx": 142 + "setId": 2, + "iconIdx": 146 }, { "icon": { @@ -3517,6 +3943,8 @@ "M742.4 443.2c82.347 0 149.333-66.987 149.333-149.333 0-24.747-6.827-47.787-17.493-68.267l-115.2 115.2-63.573-63.573 115.2-115.2c-20.48-10.667-43.52-17.493-68.267-17.493-82.347 0-149.333 66.987-149.333 149.333 0 17.493 3.413 34.133 8.96 49.493l-78.933 78.933-75.947-75.947 30.293-30.293-60.16-60.16 90.453-90.453c-49.92-49.92-130.987-49.92-180.907 0l-151.040 151.040 60.16 60.16h-120.32l-30.293 30.293 151.040 151.040 30.293-30.293v-120.747l60.16 60.16 30.293-30.293 75.947 75.947-316.16 316.16 90.453 90.453 485.547-485.12c15.36 5.547 32 8.96 49.493 8.96z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "maintenance" ], @@ -3525,15 +3953,119 @@ }, "attrs": [], "properties": { - "order": 716, - "id": 147, + "order": 1864, + "id": 146, "name": "maintenance", "prevSize": 32, "code": 59883 }, "setIdx": 0, - "setId": 0, - "iconIdx": 143 + "setId": 2, + "iconIdx": 147 + }, + { + "icon": { + "paths": [ + "M576 661.333h-149.333v-128h149.333c16.973 0 33.254 6.741 45.257 18.743s18.743 28.284 18.743 45.257c0 16.973-6.741 33.254-18.743 45.257s-28.284 18.743-45.257 18.743zM426.667 277.333h128c16.973 0 33.254 6.743 45.257 18.745s18.743 28.281 18.743 45.255c0 16.974-6.741 33.253-18.743 45.255s-28.284 18.745-45.257 18.745h-128v-128zM665.6 460.373c41.387-29.013 70.4-76.373 70.4-119.040 0-96.427-74.667-170.667-170.667-170.667h-266.667v597.333h300.373c89.6 0 158.293-72.533 158.293-161.707 0-64.853-36.693-120.32-91.733-145.92z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "mdi-format-bold" + ], + "defaultCode": 59683, + "grid": 16 + }, + "attrs": [], + "properties": { + "order": 1865, + "id": 147, + "name": "mdi-format-bold", + "prevSize": 32, + "code": 59683 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 148 + }, + { + "icon": { + "paths": [ + "M426.667 170.667v128h94.293l-145.92 341.333h-119.040v128h341.333v-128h-94.293l145.92-341.333h119.040v-128h-341.333z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "mdi-format-italic" + ], + "defaultCode": 59684, + "grid": 16 + }, + "attrs": [], + "properties": { + "order": 1866, + "id": 148, + "name": "mdi-format-italic", + "prevSize": 32, + "code": 59684 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 149 + }, + { + "icon": { + "paths": [ + "M448 298.667c-73.553 0-144.094 29.219-196.104 81.229s-81.229 122.551-81.229 196.104c0 73.553 29.219 144.094 81.229 196.105s122.551 81.229 196.104 81.229h149.333v-85.333h-149.333c-106.667 0-192-85.333-192-192s85.333-192 192-192h241.92l-131.413 131.84 60.16 60.16 234.667-234.667-234.667-234.667-60.587 60.16 131.84 131.84h-241.92zM768 768h-85.333v85.333h85.333v-85.333z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "mdi-redo-variant" + ], + "defaultCode": 59685, + "grid": 16 + }, + "attrs": [], + "properties": { + "order": 1867, + "id": 149, + "name": "mdi-redo-variant", + "prevSize": 32, + "code": 59685 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 150 + }, + { + "icon": { + "paths": [ + "M576 298.667c73.553 0 144.094 29.219 196.105 81.229s81.229 122.551 81.229 196.104c0 73.553-29.218 144.094-81.229 196.105s-122.551 81.229-196.105 81.229h-149.333v-85.333h149.333c106.667 0 192-85.333 192-192s-85.333-192-192-192h-241.92l131.413 131.84-60.16 60.16-234.667-234.667 234.667-234.667 60.587 60.16-131.84 131.84h241.92zM256 768h85.333v85.333h-85.333v-85.333z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "mdi-undo-variant" + ], + "defaultCode": 59686, + "grid": 16 + }, + "attrs": [], + "properties": { + "order": 1868, + "id": 150, + "name": "mdi-undo-variant", + "prevSize": 32, + "code": 59686 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 151 }, { "icon": { @@ -3541,6 +4073,8 @@ "M469.333 384h-85.333v-298.667h-85.333v298.667h-85.333v-298.667h-85.333v298.667c0 90.453 70.827 163.84 160 169.387v385.28h106.667v-385.28c89.173-5.547 160-78.933 160-169.387v-298.667h-85.333v298.667zM682.667 256v341.333h106.667v341.333h106.667v-853.333c-117.76 0-213.333 95.573-213.333 170.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "meal" ], @@ -3549,15 +4083,15 @@ }, "attrs": [], "properties": { - "order": 721, - "id": 152, + "order": 1869, + "id": 151, "name": "meal", "prevSize": 32, "code": 59884 }, "setIdx": 0, - "setId": 0, - "iconIdx": 144 + "setId": 2, + "iconIdx": 152 }, { "icon": { @@ -3565,6 +4099,8 @@ "M128 768h768v-85.333h-768v85.333zM128 554.667h768v-85.333h-768v85.333zM128 256v85.333h768v-85.333h-768z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "menu" ], @@ -3573,15 +4109,15 @@ }, "attrs": [], "properties": { - "order": 722, - "id": 153, + "order": 1870, + "id": 152, "name": "menu", "prevSize": 32, "code": 59687 }, "setIdx": 0, - "setId": 0, - "iconIdx": 145 + "setId": 2, + "iconIdx": 153 }, { "icon": { @@ -3589,6 +4125,8 @@ "M455.092 644.024l58.869-59.781 21.32 21.617 344.463-349.86 58.911 59.736-403.374 409.599-80.188-81.311zM279.282 605.86l344.462-349.86 58.911 59.736-403.373 409.599-195.082-198.4 58.914-59.737 136.168 138.662z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "message read" ], @@ -3597,15 +4135,15 @@ }, "attrs": [], "properties": { - "order": 723, - "id": 154, + "order": 1871, + "id": 153, "name": "message-read", "prevSize": 32, "code": 59688 }, "setIdx": 0, - "setId": 0, - "iconIdx": 146 + "setId": 2, + "iconIdx": 154 }, { "icon": { @@ -3613,6 +4151,8 @@ "M512 597.333c70.827 0 127.573-57.173 127.573-128l0.427-256c0-70.827-57.173-128-128-128s-128 57.173-128 128v256c0 70.827 57.173 128 128 128zM738.133 469.333c0 128-108.373 217.6-226.133 217.6s-226.133-89.6-226.133-217.6h-72.533c0 145.493 116.053 265.813 256 286.72v139.947h85.333v-139.947c139.947-20.48 256-140.8 256-286.72h-72.533z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "mic" ], @@ -3621,15 +4161,15 @@ }, "attrs": [], "properties": { - "order": 724, - "id": 155, + "order": 1872, + "id": 154, "name": "mic", "prevSize": 32, "code": 59885 }, "setIdx": 0, - "setId": 0, - "iconIdx": 147 + "setId": 2, + "iconIdx": 155 }, { "icon": { @@ -3637,6 +4177,8 @@ "M810.667 554.667h-597.333v-85.333h597.333v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "minus" ], @@ -3645,15 +4187,15 @@ }, "attrs": [], "properties": { - "order": 725, - "id": 156, + "order": 1873, + "id": 155, "name": "minus", "prevSize": 32, "code": 59783 }, "setIdx": 0, - "setId": 0, - "iconIdx": 148 + "setId": 2, + "iconIdx": 156 }, { "icon": { @@ -3661,6 +4203,8 @@ "M512.427 512c0-152.321 93.867-282.455 226.56-335.788 37.973-15.36 32-72.107-8.107-81.067-46.933-10.24-96.853-12.8-148.48-5.973-192.425 25.6-346.452 183.893-366.505 376.748-26.453 256.427 173.653 472.747 424.532 472.747 31.147 0 61.013-3.413 90.453-9.813 40.533-8.96 46.933-65.28 8.533-81.067-137.387-55.040-227.413-188.16-226.987-335.787z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "mode-dark" ], @@ -3669,15 +4213,15 @@ }, "attrs": [], "properties": { - "order": 726, - "id": 157, + "order": 1874, + "id": 156, "name": "mode-dark", "prevSize": 32, "code": 59784 }, "setIdx": 0, - "setId": 0, - "iconIdx": 149 + "setId": 2, + "iconIdx": 157 }, { "icon": { @@ -3685,6 +4229,8 @@ "M512 298.667c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333c117.76 0 213.333-95.573 213.333-213.333s-95.573-213.333-213.333-213.333zM85.333 554.667h85.333c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-85.333c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM853.333 554.667h85.333c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-85.333c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM469.333 85.333v85.333c0 23.467 19.2 42.667 42.667 42.667s42.667-19.2 42.667-42.667v-85.333c0-23.467-19.2-42.667-42.667-42.667s-42.667 19.2-42.667 42.667zM469.333 853.333v85.333c0 23.467 19.2 42.667 42.667 42.667s42.667-19.2 42.667-42.667v-85.333c0-23.467-19.2-42.667-42.667-42.667s-42.667 19.2-42.667 42.667zM255.573 195.413c-16.64-16.64-43.947-16.64-60.16 0-16.64 16.64-16.64 43.947 0 60.16l45.227 45.227c16.64 16.64 43.947 16.64 60.16 0s16.64-43.947 0-60.16l-45.227-45.227zM783.36 723.2c-16.64-16.64-43.947-16.64-60.16 0-16.64 16.64-16.64 43.947 0 60.16l45.227 45.227c16.64 16.64 43.947 16.64 60.16 0 16.64-16.64 16.64-43.947 0-60.16l-45.227-45.227zM828.587 255.573c16.64-16.64 16.64-43.947 0-60.16-16.64-16.64-43.947-16.64-60.16 0l-45.227 45.227c-16.64 16.64-16.64 43.947 0 60.16s43.947 16.64 60.16 0l45.227-45.227zM300.8 783.36c16.64-16.64 16.64-43.947 0-60.16-16.64-16.64-43.947-16.64-60.16 0l-45.227 45.227c-16.64 16.64-16.64 43.947 0 60.16s43.947 16.64 60.16 0l45.227-45.227z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "mode-light" ], @@ -3693,15 +4239,15 @@ }, "attrs": [], "properties": { - "order": 727, - "id": 158, + "order": 1875, + "id": 157, "name": "mode-light", "prevSize": 32, "code": 59785 }, "setIdx": 0, - "setId": 0, - "iconIdx": 150 + "setId": 2, + "iconIdx": 158 }, { "icon": { @@ -3709,6 +4255,8 @@ "M503.466 465.067c-96.853-25.174-128-51.2-128-91.734 0-46.506 43.093-78.933 115.2-78.933 75.947 0 104.107 36.267 106.667 89.6h94.296c-2.989-73.387-47.789-140.8-136.963-162.56v-93.44h-128v92.16c-82.773 17.92-149.333 71.68-149.333 154.027 0 98.56 81.493 147.626 200.533 176.213 106.667 25.6 128 63.147 128 102.829 0 29.44-20.907 76.371-115.2 76.371-87.893 0-122.453-39.251-127.147-89.6h-93.866c5.12 93.44 75.093 145.92 157.013 163.411v92.589h128v-91.731c83.2-15.789 149.334-64 149.334-151.469 0-121.173-103.681-162.56-200.534-187.733z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "money" ], @@ -3717,15 +4265,15 @@ }, "attrs": [], "properties": { - "order": 728, - "id": 159, + "order": 1876, + "id": 158, "name": "money", "prevSize": 32, "code": 59689 }, "setIdx": 0, - "setId": 0, - "iconIdx": 151 + "setId": 2, + "iconIdx": 159 }, { "icon": { @@ -3733,6 +4281,8 @@ "M682.667 512c0 46.933 38.4 85.333 85.333 85.333s85.333-38.4 85.333-85.333c0-46.933-38.4-85.333-85.333-85.333s-85.333 38.4-85.333 85.333zM597.333 512c0-46.933-38.4-85.333-85.333-85.333s-85.333 38.4-85.333 85.333c0 46.933 38.4 85.333 85.333 85.333s85.333-38.4 85.333-85.333zM341.333 512c0-46.933-38.4-85.333-85.333-85.333s-85.333 38.4-85.333 85.333c0 46.933 38.4 85.333 85.333 85.333s85.333-38.4 85.333-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "more-hori" ], @@ -3741,15 +4291,15 @@ }, "attrs": [], "properties": { - "order": 729, - "id": 160, + "order": 1877, + "id": 159, "name": "more-hori", "prevSize": 32, "code": 59786 }, "setIdx": 0, - "setId": 0, - "iconIdx": 152 + "setId": 2, + "iconIdx": 160 }, { "icon": { @@ -3757,6 +4307,8 @@ "M512 341.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM512 426.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM512 682.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "more vert" ], @@ -3765,15 +4317,15 @@ }, "attrs": [], "properties": { - "order": 730, - "id": 161, + "order": 1878, + "id": 160, "name": "more-vert", "prevSize": 32, "code": 59690 }, "setIdx": 0, - "setId": 0, - "iconIdx": 153 + "setId": 2, + "iconIdx": 161 }, { "icon": { @@ -3781,24 +4333,30 @@ "M386.763 128l-91.429 160h-103.334c-47.128 0-85.333 38.205-85.333 85.333v469.333c0 47.13 38.205 85.333 85.333 85.333h682.667c47.13 0 85.333-38.204 85.333-85.333v-469.333c0-47.128-38.204-85.333-85.333-85.333h-103.334l-91.43-160h-293.139zM697.621 288h-328.575l54.857-96h218.861l54.857 96zM192 352h682.667c11.78 0 21.333 9.551 21.333 21.333 0 106.039-85.961 192-192 192h-341.333c-106.039 0-192-85.961-192-192 0-11.782 9.551-21.333 21.333-21.333zM170.667 542.665c44.716 50.667 109.172 83.494 181.333 86.451v64.218h64v-64h234.667v64h64v-64.218c72.162-2.957 136.619-35.785 181.333-86.451v300.002c0 11.78-9.553 21.333-21.333 21.333h-682.667c-11.782 0-21.333-9.553-21.333-21.333v-300.002z" ], "width": 1067, - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "mywork" ], "defaultCode": 59728, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 731, - "id": 162, + "order": 1879, + "id": 161, "name": "mywork", "prevSize": 32, "code": 59728 }, "setIdx": 0, - "setId": 0, - "iconIdx": 154 + "setId": 2, + "iconIdx": 162 }, { "icon": { @@ -3806,6 +4364,8 @@ "M301.767 683.938l109.95-248.324c5.318-12.011 14.648-21.642 26.282-27.132l240.567-113.497c27.75-13.092 56.35 16.413 43.665 45.075l-109.948 248.326c-5.321 12.011-14.647 21.641-26.283 27.132l-240.568 113.498c-27.767 13.090-56.35-16.414-43.666-45.077zM549.632 550.848c20.783-21.453 20.783-56.243 0-77.696s-54.481-21.453-75.264 0c-20.783 21.453-20.783 56.243 0 77.696s54.481 21.453 75.264 0zM98.667 512c0-235.647 185.050-426.667 413.333-426.667s413.333 191.020 413.333 426.667c0 235.648-185.050 426.667-413.333 426.667s-413.333-191.019-413.333-426.667zM845.333 512c0-189.729-149.534-344.086-333.333-344.086s-333.333 154.357-333.333 344.086c0 189.73 149.533 344.085 333.333 344.085s333.333-154.355 333.333-344.085z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "navigate" ], @@ -3814,15 +4374,15 @@ }, "attrs": [], "properties": { - "order": 732, - "id": 163, + "order": 1880, + "id": 162, "name": "navigate", "prevSize": 32, "code": 59886 }, "setIdx": 0, - "setId": 0, - "iconIdx": 155 + "setId": 2, + "iconIdx": 163 }, { "icon": { @@ -3830,6 +4390,8 @@ "M870.071 465.967c13.154 22.272 20.595 46.033 20.595 74.756 0 66.022-55.825 128.371-128.73 128.371h-54.72c7.381 19.217 13.274 42.197 13.274 69.811 0 109.188-56.533 157.094-142.903 157.094-92.412 0-87.138-142.4-107.639-162.901-34.121-34.121-74.423-99.669-103.141-125.099h-148.14c-26.51 0-48-21.491-48-48v-360c0-26.51 21.49-48 48-48h96c22.339 0 41.112 15.261 46.467 35.925 66.762-1.501 112.59-59.91 266.702-59.91 10.833 0 22.831-0.015 33.331-0.015 115.674 0 167.979 59.134 169.408 142.995 19.981 27.637 30.451 64.683 26.014 100.485 14.78 27.678 20.493 60.516 13.483 94.487zM777.446 385.22c18.842-31.695 1.89-74.115-20.911-86.355 11.55-73.17-26.411-98.85-79.68-98.85h-56.73c-107.456 0-177.041 56.73-257.459 56.73v279.255h16.38c42.54 0 101.969 106.334 141.811 146.189 42.539 42.543 28.365 113.446 56.73 141.811 70.903 0 70.903-49.472 70.903-85.094 0-58.756-42.539-85.082-42.539-141.811h155.985c31.663 0 56.593-28.365 56.73-56.73 0.137-28.348-19.23-56.717-33.404-56.717 20.233-21.833 24.555-67.852-7.817-98.428zM302.667 248c0-19.883-16.117-36-36-36s-36 16.117-36 36c0 19.883 16.117 36 36 36s36-16.117 36-36z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "negative" ], @@ -3838,15 +4400,15 @@ }, "attrs": [], "properties": { - "order": 733, - "id": 164, + "order": 1881, + "id": 163, "name": "negative", "prevSize": 32, "code": 59691 }, "setIdx": 0, - "setId": 0, - "iconIdx": 156 + "setId": 2, + "iconIdx": 164 }, { "icon": { @@ -3854,6 +4416,8 @@ "M213.333 128c-47.36 0-85.333 37.973-85.333 85.333v597.333c0 22.63 8.99 44.335 24.994 60.339s37.708 24.994 60.34 24.994h597.333c22.63 0 44.335-8.99 60.339-24.994s24.994-37.709 24.994-60.339v-298.667h-85.333v298.667h-597.333v-597.333h298.667v-85.333h-298.667zM758.613 170.667c-7.68 0.065-15.027 3.127-20.48 8.533l-52.053 51.627 106.667 106.667 52.053-51.627c11.093-11.093 11.093-29.867 0-40.533l-66.133-66.133c-5.547-5.547-12.8-8.533-20.053-8.533zM655.787 261.12l-314.453 314.88v106.667h106.667l314.453-314.88-106.667-106.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "new message" ], @@ -3862,15 +4426,15 @@ }, "attrs": [], "properties": { - "order": 734, - "id": 165, + "order": 1882, + "id": 164, "name": "new-message", "prevSize": 32, "code": 59692 }, "setIdx": 0, - "setId": 0, - "iconIdx": 157 + "setId": 2, + "iconIdx": 165 }, { "icon": { @@ -3878,6 +4442,8 @@ "M341.333 682.667h341.333v85.333h-341.333v-85.333zM341.333 512h341.333v85.333h-341.333v-85.333zM597.333 85.333h-341.333c-46.933 0-85.333 38.4-85.333 85.333v682.667c0 46.933 37.973 85.333 84.907 85.333h512.427c46.933 0 85.333-38.4 85.333-85.333v-512l-256-256zM768 853.333h-512v-682.667h298.667v213.333h213.333v469.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "note" ], @@ -3886,15 +4452,15 @@ }, "attrs": [], "properties": { - "order": 735, - "id": 166, + "order": 1883, + "id": 165, "name": "note", "prevSize": 32, "code": 59788 }, "setIdx": 0, - "setId": 0, - "iconIdx": 158 + "setId": 2, + "iconIdx": 166 }, { "icon": { @@ -3902,6 +4468,8 @@ "M511.999 938.669c46.933 0 85.333-38.4 85.333-85.338h-170.666c0 46.938 37.973 85.338 85.333 85.338zM768 682.669v-213.335c0-130.987-69.971-240.64-192.001-269.653v-29.014c0-35.413-28.587-64-64-64s-64 28.587-64 64v29.014c-122.453 29.013-192 138.24-192 269.653v213.335l-85.333 85.331v42.669h682.665v-42.669l-85.331-85.331z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "notification" ], @@ -3910,15 +4478,15 @@ }, "attrs": [], "properties": { - "order": 736, - "id": 167, + "order": 1884, + "id": 166, "name": "notification", "prevSize": 32, "code": 59693 }, "setIdx": 0, - "setId": 0, - "iconIdx": 159 + "setId": 2, + "iconIdx": 167 }, { "icon": { @@ -3927,6 +4495,8 @@ ], "width": 975, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "notification-silence" ], @@ -3935,15 +4505,15 @@ }, "attrs": [], "properties": { - "order": 737, - "id": 168, + "order": 1885, + "id": 167, "name": "notification-silence", "prevSize": 32, "code": 59743 }, "setIdx": 0, - "setId": 0, - "iconIdx": 160 + "setId": 2, + "iconIdx": 168 }, { "icon": { @@ -3951,6 +4521,8 @@ "M853.333 797.44l-628.48-648.533-54.187 54.187 119.467 119.467v0.427c-22.187 42.24-34.133 92.16-34.133 145.92v213.333l-85.333 85.333v42.667h585.813l85.333 85.333 54.187-54.187-42.667-43.947zM512 938.667c47.36 0 85.333-37.973 85.333-85.333h-170.667c0 47.36 37.973 85.333 85.333 85.333zM768 626.347v-157.013c0-131.413-69.973-240.64-192-269.653v-29.013c0-35.413-28.587-64-64-64s-64 28.587-64 64v29.013c-6.4 1.28-12.373 3.413-17.92 5.12-4.267 1.28-8.533 2.987-12.8 4.693h-0.427c-0.427 0-0.427 0-0.853 0.427-9.813 3.84-19.627 8.533-29.013 13.227 0 0-0.427 0-0.427 0.427l381.44 402.773z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "notifications-off" ], @@ -3959,15 +4531,15 @@ }, "attrs": [], "properties": { - "order": 738, - "id": 169, + "order": 1886, + "id": 168, "name": "notifications-off", "prevSize": 32, "code": 59720 }, "setIdx": 0, - "setId": 0, - "iconIdx": 161 + "setId": 2, + "iconIdx": 169 }, { "icon": { @@ -3975,6 +4547,8 @@ "M512 938.667c46.933 0 85.333-38.4 85.333-85.333h-170.667c0 46.933 38.4 85.333 85.333 85.333zM512 277.333c106.24 0 170.667 86.187 170.667 192v4.267l85.333 85.333v-89.6c0-130.987-69.547-240.64-192-269.653v-29.013c0-35.413-28.587-64-64-64s-64 28.587-64 64v29.013c-10.24 2.56-20.053 6.4-29.44 9.813l69.973 69.973c7.68-0.853 15.36-2.133 23.467-2.133zM230.827 142.933l-60.16 60.16 119.893 119.893c-22.187 42.667-34.56 92.587-34.56 146.347v213.333l-85.333 85.333v42.667h607.573l74.24 74.24 60.16-60.16-681.813-681.813zM682.667 725.333h-341.333v-256c0-29.013 5.12-56.32 14.507-81.067l326.827 326.827v10.24z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "notifications-off-outlined" ], @@ -3983,15 +4557,15 @@ }, "attrs": [], "properties": { - "order": 739, - "id": 170, + "order": 1887, + "id": 169, "name": "notifications-off-outlined", "prevSize": 32, "code": 59695 }, "setIdx": 0, - "setId": 0, - "iconIdx": 162 + "setId": 2, + "iconIdx": 170 }, { "icon": { @@ -4000,6 +4574,8 @@ ], "width": 832, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "open-in-full-black-24dp" ], @@ -4008,15 +4584,15 @@ }, "attrs": [], "properties": { - "order": 740, - "id": 171, + "order": 1888, + "id": 170, "name": "open-in-small", "prevSize": 32, "code": 59742 }, "setIdx": 0, - "setId": 0, - "iconIdx": 163 + "setId": 2, + "iconIdx": 171 }, { "icon": { @@ -4024,6 +4600,8 @@ "M810.667 810.667h-597.333v-597.333h298.667v-85.333h-298.667c-47.36 0-85.333 38.4-85.333 85.333v597.333c0 46.933 37.973 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-298.667h-85.333v298.667zM597.333 128v85.333h153.173l-419.413 419.413 60.16 60.16 419.413-419.413v153.173h85.333v-298.667h-298.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "open-new" ], @@ -4032,15 +4610,15 @@ }, "attrs": [], "properties": { - "order": 741, - "id": 172, + "order": 1889, + "id": 171, "name": "open-new", "prevSize": 32, "code": 59889 }, "setIdx": 0, - "setId": 0, - "iconIdx": 164 + "setId": 2, + "iconIdx": 172 }, { "icon": { @@ -4048,6 +4626,8 @@ "M716.373 247.467l-119.040-119.467h298.667v298.667l-119.040-119.467-174.507 174.507-60.16-60.16 174.080-174.080zM810.667 512v177.92l85.333 85.333v-263.253h-85.333zM843.947 964.693l-68.693-68.693h-561.92c-47.36 0-85.333-38.4-85.333-85.333v-561.92l-68.693-68.693 60.16-60.16 784.213 784.213-59.733 60.587zM689.92 810.667l-208.213-208.213-67.84 67.84-60.16-60.16 67.84-67.84-208.213-208.213v476.587h476.586zM334.080 213.333h177.92v-85.333h-263.253l85.333 85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "open-new-off" ], @@ -4056,15 +4636,15 @@ }, "attrs": [], "properties": { - "order": 742, - "id": 173, + "order": 1890, + "id": 172, "name": "open-new-off", "prevSize": 32, "code": 59888 }, "setIdx": 0, - "setId": 0, - "iconIdx": 165 + "setId": 2, + "iconIdx": 173 }, { "icon": { @@ -4073,6 +4653,8 @@ ], "width": 998, "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "open-shift" ], @@ -4081,38 +4663,44 @@ }, "attrs": [], "properties": { - "order": 743, - "id": 174, + "order": 1891, + "id": 173, "name": "open-shift", "prevSize": 32, "code": 59746 }, "setIdx": 0, - "setId": 0, - "iconIdx": 166 + "setId": 2, + "iconIdx": 174 }, { "icon": { "paths": [ "M860.16 593.92h-73.728v-40.96c0-40.96-32.768-73.728-73.728-73.728h-172.032v-49.152h73.728c32.768 0 61.44-28.672 61.44-61.44v-204.8c0-32.768-28.672-61.44-61.44-61.44h-204.8c-32.768 0-61.44 28.672-61.44 61.44v204.8c0 32.768 28.672 61.44 61.44 61.44h73.728v49.152h-176.128c-40.96 0-73.728 32.768-73.728 73.728v40.96h-69.632c-32.768 0-61.44 28.672-61.44 61.44v204.8c0 32.768 28.672 61.44 61.44 61.44h204.8c32.768 0 61.44-28.672 61.44-61.44v-204.8c0-32.768-28.672-61.44-61.44-61.44h-69.632v-40.96c0-4.096 4.096-8.192 8.192-8.192h409.6c4.096 0 8.192 4.096 8.192 8.192v40.96h-73.728c-32.768 0-61.44 28.672-61.44 61.44v204.8c0 32.768 28.672 61.44 61.44 61.44h204.8c32.768 0 61.44-28.672 61.44-61.44v-204.8c4.096-32.768-24.576-61.44-57.344-61.44zM368.64 655.36v204.8h-204.8v-204.8h204.8zM409.6 368.64v-204.8h204.8v204.8h-204.8zM860.16 860.16h-204.8v-204.8h204.8v204.8z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "org" ], "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 744, - "id": 175, + "order": 1892, + "id": 174, "name": "org", "prevSize": 32, "code": 59805 }, "setIdx": 0, - "setId": 0, - "iconIdx": 167 + "setId": 2, + "iconIdx": 175 }, { "icon": { @@ -4120,6 +4708,8 @@ "M512 85.333c-235.093 0-426.667 191.573-426.667 426.667s191.573 426.667 426.667 426.667c58.88 0 106.667-47.787 106.667-106.667 0-26.027-9.813-51.2-27.307-71.253-3.413-4.267-5.547-8.96-5.547-14.080 0-11.947 9.387-21.333 21.333-21.333h75.52c141.227 0 256-114.773 256-256 0-211.627-191.573-384-426.667-384zM746.667 554.667c-35.413 0-64-28.587-64-64s28.587-64 64-64c35.413 0 64 28.587 64 64s-28.587 64-64 64zM618.667 384c-35.413 0-64-28.587-64-64s28.587-64 64-64c35.413 0 64 28.587 64 64s-28.587 64-64 64zM213.333 490.667c0-35.413 28.587-64 64-64s64 28.587 64 64c0 35.413-28.587 64-64 64s-64-28.587-64-64zM469.333 320c0 35.413-28.587 64-64 64s-64-28.587-64-64c0-35.413 28.587-64 64-64s64 28.587 64 64z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "palette" ], @@ -4128,15 +4718,15 @@ }, "attrs": [], "properties": { - "order": 745, - "id": 176, + "order": 1893, + "id": 175, "name": "palette", "prevSize": 32, "code": 59890 }, "setIdx": 0, - "setId": 0, - "iconIdx": 168 + "setId": 2, + "iconIdx": 176 }, { "icon": { @@ -4144,6 +4734,8 @@ "M597.333 85.333h-341.333c-46.933 0-84.907 38.4-84.907 85.333l-0.427 682.667c0 46.933 37.973 85.333 84.907 85.333h512.427c46.933 0 85.333-38.4 85.333-85.333v-512l-256-256zM554.667 384v-234.667l234.667 234.667h-234.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "paper" ], @@ -4152,15 +4744,15 @@ }, "attrs": [], "properties": { - "order": 746, - "id": 177, + "order": 1894, + "id": 176, "name": "paper", "prevSize": 32, "code": 59789 }, "setIdx": 0, - "setId": 0, - "iconIdx": 169 + "setId": 2, + "iconIdx": 177 }, { "icon": { @@ -4168,6 +4760,8 @@ "M472.747 87.253c-72.777 7.153-138.707 31.396-195.334 68.631l1.627-1.005c-26.097 16.873-48.76 35.564-69.059 56.554l-0.103 0.107c-76.764 76.183-124.283 181.739-124.283 298.394 0 5.528 0.107 11.030 0.318 16.506l-0.024-0.788c3.029 90.411 31.531 171.008 86.187 244.053 16.939 22.613 54.272 60.757 75.392 77.099 61.525 47.531 127.445 75.819 204.8 87.893 27.605 4.309 91.861 4.309 119.467 0 95.488-14.933 175.104-54.912 241.579-121.387s106.453-146.091 121.387-241.579c4.309-27.605 4.309-91.861 0-119.467-12.075-77.397-40.448-143.445-87.893-204.8-14.379-18.56-51.541-55.723-70.272-70.229-88.192-68.224-194.304-99.669-303.787-89.984zM543.317 172.416c80.56 7.432 151.864 42.097 205.726 94.577l-0.073-0.070c64.183 62 104.035 148.833 104.035 244.973 0 54.378-12.749 105.778-35.422 151.375l0.891-1.979c-18.642 38.173-42.775 70.691-71.813 98.063l-0.166 0.155c-24.593 23.856-53.119 43.843-84.478 58.861l-1.922 0.829c-43.256 21.499-94.207 34.080-148.096 34.080s-104.84-12.581-150.075-34.966l1.979 0.886c-45.384-21.996-83.54-52.209-113.979-89.035l-0.453-0.565c-85.291-101.931-102.699-247.381-43.989-366.933 56.012-113.512 170.416-190.5 302.933-191.785l0.171-0.001c8.917-0.085 24.533 0.597 34.731 1.536zM256 512v42.667h512v-85.333h-512v42.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "partial approval" ], @@ -4176,15 +4770,15 @@ }, "attrs": [], "properties": { - "order": 747, - "id": 178, + "order": 1895, + "id": 177, "name": "partially-approved", "prevSize": 32, "code": 59738 }, "setIdx": 0, - "setId": 0, - "iconIdx": 170 + "setId": 2, + "iconIdx": 178 }, { "icon": { @@ -4193,6 +4787,8 @@ "M950.583 570.692l-170.803-341.601c-7.057-14.12-24.081-19.756-38.199-12.753l-85.402 42.7c-14.063 7.060-19.755 24.14-12.753 38.202l15.031 29.947h-74.867l-199.325 199.268 22.261 26.756c17.194 20.612 46.516 26.645 69.8 14.293l79.194-41.28 173.935 144.102 72.644-56.026 12.241 24.482c5.009 9.963 15.087 15.714 25.451 15.714 4.271 0 8.597-0.969 12.753-3.017l85.402-42.701c14.003-6.946 19.639-24.026 12.638-38.089z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "partner" ], @@ -4201,15 +4797,15 @@ }, "attrs": [], "properties": { - "order": 748, - "id": 179, + "order": 1896, + "id": 178, "name": "partner", "prevSize": 32, "code": 59891 }, "setIdx": 0, - "setId": 0, - "iconIdx": 171 + "setId": 2, + "iconIdx": 179 }, { "icon": { @@ -4217,23 +4813,25 @@ "M588.8 512h38.4v-115.2h-38.4v115.2zM435.2 435.2h38.4v-38.4h-38.4v38.4zM819.2 128h-460.8c-42.24 0-76.8 34.56-76.8 76.8v460.8c0 42.24 34.56 76.8 76.8 76.8h460.8c42.24 0 76.8-34.56 76.8-76.8v-460.8c0-42.24-34.56-76.8-76.8-76.8zM512 435.2c0 21.12-17.28 38.4-38.4 38.4h-38.4v57.6c0 10.752-8.448 19.2-19.2 19.2s-19.2-8.448-19.2-19.2v-153.6c0-10.752 8.448-19.2 19.2-19.2h57.6c21.12 0 38.4 17.28 38.4 38.4v38.4zM665.6 512c0 21.12-17.28 38.4-38.4 38.4h-57.6c-10.752 0-19.2-8.448-19.2-19.2v-153.6c0-10.752 8.448-19.2 19.2-19.2h57.6c21.12 0 38.4 17.28 38.4 38.4v115.2zM761.6 396.8h-19.2v38.4h19.2c10.752 0 19.2 8.448 19.2 19.2s-8.448 19.2-19.2 19.2h-19.2v57.6c0 10.752-8.448 19.2-19.2 19.2s-19.2-8.448-19.2-19.2v-153.6c0-10.752 8.448-19.2 19.2-19.2h38.4c10.752 0 19.2 8.448 19.2 19.2s-8.448 19.2-19.2 19.2zM166.4 281.6c-21.12 0-38.4 17.28-38.4 38.4v499.2c0 42.24 34.56 76.8 76.8 76.8h499.2c21.12 0 38.4-17.28 38.4-38.4s-17.28-38.4-38.4-38.4h-499.2v-499.2c0-21.12-17.28-38.4-38.4-38.4z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "PDF" ], - "defaultCode": 59694, + "defaultCode": 59695, "grid": 16 }, "attrs": [], "properties": { - "order": 569, - "id": 0, + "order": 1897, + "id": 179, "name": "pdf", "prevSize": 32, - "code": 59694 + "code": 59696 }, "setIdx": 0, - "setId": 0, - "iconIdx": 172 + "setId": 2, + "iconIdx": 180 }, { "icon": { @@ -4241,6 +4839,8 @@ "M810.667 128h-178.347c-17.92-49.493-64.853-85.333-120.32-85.333s-102.4 35.84-120.32 85.333h-178.347c-46.933 0-85.333 38.4-85.333 85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333zM512 128c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667zM512 298.667c70.827 0 128 57.173 128 128s-57.173 128-128 128c-70.827 0-128-57.173-128-128s57.173-128 128-128zM768 810.667h-512v-59.733c0-85.333 170.667-132.267 256-132.267s256 46.933 256 132.267v59.733z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "person-assign" ], @@ -4249,15 +4849,15 @@ }, "attrs": [], "properties": { - "order": 750, - "id": 181, + "order": 1898, + "id": 180, "name": "person-assign", "prevSize": 32, "code": 59892 }, "setIdx": 0, - "setId": 0, - "iconIdx": 174 + "setId": 2, + "iconIdx": 181 }, { "icon": { @@ -4268,6 +4868,8 @@ "M736 576h-32v128l112 67.2 16-26.24-96-56.96v-112z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "person-clock" ], @@ -4276,15 +4878,15 @@ }, "attrs": [], "properties": { - "order": 751, - "id": 182, + "order": 1899, + "id": 181, "name": "person-clock", "prevSize": 32, "code": 59893 }, "setIdx": 0, - "setId": 0, - "iconIdx": 175 + "setId": 2, + "iconIdx": 182 }, { "icon": { @@ -4294,6 +4896,8 @@ "M704 853.333c82.432 0 149.333-66.901 149.333-149.333s-66.901-149.333-149.333-149.333c-82.432 0-149.333 66.901-149.333 149.333s66.901 149.333 149.333 149.333zM689.067 629.333h29.867v89.6h-29.867v-89.6zM689.067 748.8h29.867v29.867h-29.867v-29.867z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "person-info" ], @@ -4302,15 +4906,15 @@ }, "attrs": [], "properties": { - "order": 752, - "id": 183, + "order": 1900, + "id": 182, "name": "person-info", "prevSize": 32, "code": 59894 }, "setIdx": 0, - "setId": 0, - "iconIdx": 176 + "setId": 2, + "iconIdx": 183 }, { "icon": { @@ -4320,6 +4924,8 @@ "M736.969 512l-139.635 104.725v50.428c0 86.106 59.58 166.63 139.635 186.18 80.060-19.55 139.639-100.075 139.639-186.18v-50.428l-139.639-104.725z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "person-manager" ], @@ -4328,15 +4934,15 @@ }, "attrs": [], "properties": { - "order": 753, - "id": 184, + "order": 1901, + "id": 183, "name": "person-manager", "prevSize": 32, "code": 59895 }, "setIdx": 0, - "setId": 0, - "iconIdx": 177 + "setId": 2, + "iconIdx": 184 }, { "icon": { @@ -4346,6 +4952,8 @@ "M725.76 512l170.24 170.667-170.24 170.667v-128h-171.093v-85.333h171.093v-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "person-move" ], @@ -4354,15 +4962,15 @@ }, "attrs": [], "properties": { - "order": 754, - "id": 185, + "order": 1902, + "id": 184, "name": "person-move", "prevSize": 32, "code": 59896 }, "setIdx": 0, - "setId": 0, - "iconIdx": 178 + "setId": 2, + "iconIdx": 185 }, { "icon": { @@ -4370,6 +4978,8 @@ "M703.573 661.333v-74.667l-106.24 106.667 106.24 106.667v-74.667h235.093v-64h-235.093zM832.427 842.667h-235.093v64h235.093v74.667l106.24-106.667-106.24-106.667v74.667zM405.333 234.667c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM245.333 379.733l-117.333 601.6h89.6l74.667-341.333 91.733 85.333v256h85.333v-322.133l-87.467-87.467 25.6-128c55.467 68.267 138.667 110.933 232.533 110.933v-85.333c-78.933 0-147.2-42.667-185.6-104.533l-40.533-68.267c-14.933-25.6-42.667-40.533-72.533-40.533-10.667 0-21.333 2.133-32 6.4l-224 91.733v200.533h85.333v-142.933l74.667-32z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "person-swap" ], @@ -4378,15 +4988,15 @@ }, "attrs": [], "properties": { - "order": 755, - "id": 186, + "order": 1903, + "id": 185, "name": "person-swap", "prevSize": 32, "code": 59897 }, "setIdx": 0, - "setId": 0, - "iconIdx": 179 + "setId": 2, + "iconIdx": 186 }, { "icon": { @@ -4394,6 +5004,8 @@ "M576 234.667c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM418.133 379.733l-119.467 601.6h89.6l76.8-341.333 89.6 85.333v256h85.333v-320l-89.6-85.333 25.6-128c55.467 64 140.8 106.667 234.667 106.667v-85.333c-81.067 0-149.333-42.667-183.467-102.4l-42.667-68.267c-17.067-25.6-42.667-42.667-72.533-42.667-12.8 0-21.333 4.267-34.133 4.267l-221.867 93.867v200.533h85.333v-145.067l76.8-29.867z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "person-walk" ], @@ -4402,15 +5014,15 @@ }, "attrs": [], "properties": { - "order": 756, - "id": 187, + "order": 1904, + "id": 186, "name": "person-walk", "prevSize": 32, "code": 59898 }, "setIdx": 0, - "setId": 0, - "iconIdx": 180 + "setId": 2, + "iconIdx": 187 }, { "icon": { @@ -4418,6 +5030,8 @@ "M725.333 43.093l-426.667-0.427c-46.933 0-85.333 38.4-85.333 85.333v768c0 46.933 38.4 85.333 85.333 85.333h426.667c46.933 0 85.333-38.4 85.333-85.333v-768c0-46.933-38.4-84.907-85.333-84.907zM725.333 810.667h-426.667v-597.333h426.667v597.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "phone" ], @@ -4426,15 +5040,15 @@ }, "attrs": [], "properties": { - "order": 757, - "id": 188, + "order": 1905, + "id": 187, "name": "phone", "prevSize": 32, "code": 59899 }, "setIdx": 0, - "setId": 0, - "iconIdx": 181 + "setId": 2, + "iconIdx": 188 }, { "icon": { @@ -4442,6 +5056,8 @@ "M682.643 383.999v-213.333h42.669c23.469 0 42.669-19.2 42.669-42.667s-19.2-42.667-42.669-42.667h-426.666c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667h42.667v213.333c0 70.827-57.174 128-128 128v85.333h254.72v298.668l42.666 42.662 42.667-42.662v-298.668h257.277v-85.333c-70.822 0-128-57.173-128-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "pin" ], @@ -4450,39 +5066,45 @@ }, "attrs": [], "properties": { - "order": 758, - "id": 189, + "order": 1906, + "id": 188, "name": "pin", "prevSize": 32, "code": 59697 }, "setIdx": 0, - "setId": 0, - "iconIdx": 182 + "setId": 2, + "iconIdx": 189 }, { "icon": { "paths": [ "M675.84 389.12v-204.8h40.96c22.528 0 40.96-18.432 40.96-40.96s-18.432-40.96-40.96-40.96h-409.6c-22.528 0-40.96 18.432-40.96 40.96s18.432 40.96 40.96 40.96h40.96v204.8c0 67.994-54.886 122.88-122.88 122.88v81.92h244.531v286.72l40.96 40.96 40.96-40.96v-286.72h246.989v-81.92c-67.994 0-122.88-54.886-122.88-122.88z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "pinboard" ], "defaultCode": 59729, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 759, - "id": 190, + "order": 1907, + "id": 189, "name": "pinboard", "prevSize": 32, "code": 59729 }, "setIdx": 0, - "setId": 0, - "iconIdx": 183 + "setId": 2, + "iconIdx": 190 }, { "icon": { @@ -4490,6 +5112,8 @@ "M810.667 554.667h-256v256h-85.333v-256h-256v-85.333h256v-256h85.333v256h256v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "plus" ], @@ -4498,15 +5122,15 @@ }, "attrs": [], "properties": { - "order": 760, - "id": 191, + "order": 1908, + "id": 190, "name": "plus", "prevSize": 32, "code": 59791 }, "setIdx": 0, - "setId": 0, - "iconIdx": 184 + "setId": 2, + "iconIdx": 191 }, { "icon": { @@ -4515,6 +5139,8 @@ "M819.2 384c42.24 0 76.8 33.28 76.8 73.954v406.758c0 40.674-34.56 73.954-76.8 73.954h-614.4c-42.24 0-76.8-33.28-76.8-73.954v-406.758c0-40.674 34.56-73.954 76.8-73.954h614.4zM554.667 469.333h-85.333v384h85.333v-384z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "point-gift" ], @@ -4523,15 +5149,15 @@ }, "attrs": [], "properties": { - "order": 761, - "id": 192, + "order": 1909, + "id": 191, "name": "point-gift", "prevSize": 32, "code": 59900 }, "setIdx": 0, - "setId": 0, - "iconIdx": 185 + "setId": 2, + "iconIdx": 192 }, { "icon": { @@ -4539,6 +5165,8 @@ "M85.333 512c0-235.52 190.72-426.667 426.24-426.667 235.947 0 427.093 191.147 427.093 426.667s-191.147 426.667-427.093 426.667c-235.52 0-426.24-191.147-426.24-426.667zM481.067 704.64l30.933 28.16 31.774-28.71c109.397-99.413 181.559-164.988 181.559-245.423 0-65.707-51.627-117.333-117.333-117.333-37.12 0-72.747 17.28-96 44.587-23.253-27.307-58.88-44.587-96-44.587-65.707 0-117.333 51.627-117.333 117.333 0 80.572 72.414 146.24 182.131 245.73l0.269 0.243z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "point-heart" ], @@ -4547,15 +5175,15 @@ }, "attrs": [], "properties": { - "order": 762, - "id": 193, + "order": 1910, + "id": 192, "name": "point-heart", "prevSize": 32, "code": 59901 }, "setIdx": 0, - "setId": 0, - "iconIdx": 186 + "setId": 2, + "iconIdx": 193 }, { "icon": { @@ -4565,6 +5193,8 @@ "M789.333 128c-105.984 0-192 86.016-192 192s86.016 192 192 192c105.984 0 192-86.016 192-192s-86.016-192-192-192zM806.229 430.592v23.808h-33.6v-24.768c-14.208-3.456-45.888-14.784-57.984-56.832l31.68-12.864c1.152 4.224 11.136 40.128 46.080 40.128 17.856 0 38.016-9.216 38.016-30.912 0-18.432-13.44-28.032-43.776-38.976-21.12-7.488-64.32-19.776-64.32-63.552 0-1.92 0.192-46.080 50.304-56.832v-24.192h33.6v23.808c35.328 6.144 48.192 34.368 51.072 42.816l-30.336 12.864c-2.112-6.72-11.328-25.728-36.48-25.728-13.44 0-34.752 7.104-34.752 26.688 0 18.24 16.512 25.152 50.688 36.48 46.080 15.936 57.792 39.36 57.792 66.24 0 50.496-48 60.096-57.984 61.824z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "point-money" ], @@ -4573,15 +5203,15 @@ }, "attrs": [], "properties": { - "order": 763, - "id": 194, + "order": 1911, + "id": 193, "name": "point-money", "prevSize": 32, "code": 59902 }, "setIdx": 0, - "setId": 0, - "iconIdx": 187 + "setId": 2, + "iconIdx": 194 }, { "icon": { @@ -4589,6 +5219,8 @@ "M511.573 85.333c-235.52 0-426.24 191.147-426.24 426.667s190.72 426.667 426.24 426.667c235.947 0 427.093-191.147 427.093-426.667s-191.147-426.667-427.093-426.667zM692.48 768l-180.48-108.8-180.48 108.8 47.787-205.227-159.147-137.813 209.92-17.92 81.92-193.707 81.92 193.28 209.92 17.92-159.147 137.813 47.787 205.653z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "point-star" ], @@ -4597,15 +5229,15 @@ }, "attrs": [], "properties": { - "order": 764, - "id": 195, + "order": 1912, + "id": 194, "name": "point-star", "prevSize": 32, "code": 59903 }, "setIdx": 0, - "setId": 0, - "iconIdx": 188 + "setId": 2, + "iconIdx": 195 }, { "icon": { @@ -4613,6 +5245,8 @@ "M384 170.667c-188.587 0-341.333 152.747-341.333 341.333s152.747 341.333 341.333 341.333c188.587 0 341.333-152.747 341.333-341.333s-152.747-341.333-341.333-341.333zM512 448h-85.333v213.333h-85.333v-213.333h-85.333v-64h256v64zM864 160l117.333 53.333-117.333 53.333-53.333 117.333-53.333-117.333-117.333-53.333 117.333-53.333 53.333-117.333 53.333 117.333zM864 757.333l117.333 53.333-117.333 53.333-53.333 117.333-53.333-117.333-117.333-53.333 117.333-53.333 53.333-117.333 53.333 117.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "point-token" ], @@ -4621,15 +5255,15 @@ }, "attrs": [], "properties": { - "order": 765, - "id": 196, + "order": 1913, + "id": 195, "name": "point-token", "prevSize": 32, "code": 59904 }, "setIdx": 0, - "setId": 0, - "iconIdx": 189 + "setId": 2, + "iconIdx": 196 }, { "icon": { @@ -4637,6 +5271,8 @@ "M870.071 558.033c13.154-22.272 20.595-46.033 20.595-74.756 0-66.024-55.825-128.372-128.73-128.372h-54.72c7.381-19.215 13.274-42.195 13.274-69.81 0-109.191-56.533-157.095-142.903-157.095-92.412 0-87.138 142.4-107.639 162.9-34.121 34.121-74.423 99.671-103.141 125.1h-148.14c-26.51 0-48 21.491-48 48v360c0 26.509 21.49 48 48 48h96c22.339 0 41.112-15.262 46.467-35.925 66.762 1.502 112.59 59.908 266.702 59.908 10.833 0 22.831 0.017 33.331 0.017 115.674 0 167.979-59.136 169.408-142.993 19.981-27.639 30.451-64.687 26.014-100.489 14.78-27.678 20.493-60.514 13.483-94.485zM777.446 638.78c18.842 31.697 1.89 74.116-20.911 86.357 11.55 73.169-26.411 98.846-79.68 98.846h-56.73c-107.456 0-177.041-56.73-257.459-56.73v-279.253h16.38c42.54 0 101.969-106.335 141.811-146.19 42.539-42.54 28.365-113.445 56.73-141.81 70.903 0 70.903 49.47 70.903 85.095 0 58.755-42.539 85.080-42.539 141.811h155.985c31.663 0 56.593 28.365 56.73 56.73 0.137 28.348-19.23 56.717-33.404 56.717 20.233 21.833 24.555 67.853-7.817 98.428zM302.667 776c0 19.883-16.117 35.998-36 35.998s-36-16.115-36-35.998c0-19.883 16.117-35.998 36-35.998s36 16.115 36 35.998z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "positive" ], @@ -4645,15 +5281,15 @@ }, "attrs": [], "properties": { - "order": 766, - "id": 197, + "order": 1914, + "id": 196, "name": "positive", "prevSize": 32, "code": 59698 }, "setIdx": 0, - "setId": 0, - "iconIdx": 190 + "setId": 2, + "iconIdx": 197 }, { "icon": { @@ -4661,6 +5297,8 @@ "M810.667 128h-597.333c-22.632 0-44.337 8.99-60.34 24.994s-24.994 37.708-24.994 60.34v597.333c0 22.63 8.99 44.335 24.994 60.339s37.708 24.994 60.34 24.994h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-22.632-8.99-44.337-24.994-60.34s-37.709-24.994-60.339-24.994zM810.667 810.667h-597.333v-512h597.333v512zM576 554.667c0 35.413-28.587 64-64 64s-64-28.587-64-64c0-35.413 28.587-64 64-64s64 28.587 64 64zM512 384c-116.48 0-215.893 70.827-256 170.667 40.107 99.84 139.52 170.667 256 170.667s215.893-70.827 256-170.667c-40.107-99.84-139.52-170.667-256-170.667zM512 661.333c-28.288 0-55.42-11.238-75.426-31.241-20.003-20.006-31.241-47.138-31.241-75.426s11.238-55.42 31.241-75.426c20.006-20.002 47.138-31.241 75.426-31.241s55.42 11.238 75.426 31.241c20.002 20.006 31.241 47.138 31.241 75.426s-11.238 55.42-31.241 75.426c-20.006 20.002-47.138 31.241-75.426 31.241z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "preview" ], @@ -4669,15 +5307,15 @@ }, "attrs": [], "properties": { - "order": 767, - "id": 198, + "order": 1915, + "id": 197, "name": "preview", "prevSize": 32, "code": 59699 }, "setIdx": 0, - "setId": 0, - "iconIdx": 191 + "setId": 2, + "iconIdx": 198 }, { "icon": { @@ -4685,6 +5323,8 @@ "M810.667 341.333h-597.333c-70.827 0-128 57.173-128 128v256h170.667v170.667h512v-170.667h170.667v-256c0-70.827-57.173-128-128-128zM682.667 810.667h-341.333v-213.333h341.333v213.333zM810.667 512c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667zM768 128h-512v170.667h512v-170.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "print" ], @@ -4693,15 +5333,15 @@ }, "attrs": [], "properties": { - "order": 768, - "id": 199, + "order": 1916, + "id": 198, "name": "print", "prevSize": 32, "code": 59792 }, "setIdx": 0, - "setId": 0, - "iconIdx": 192 + "setId": 2, + "iconIdx": 199 }, { "icon": { @@ -4709,6 +5349,8 @@ "M512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM512 213.333c70.827 0 128 57.173 128 128s-57.173 128-128 128c-70.827 0-128-57.173-128-128s57.173-128 128-128zM512 819.2c-106.667 0-200.96-54.613-256-137.387 1.28-84.907 170.667-131.413 256-131.413 84.907 0 254.72 46.507 256 131.413-55.040 82.773-149.333 137.387-256 137.387z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "profile" ], @@ -4717,15 +5359,15 @@ }, "attrs": [], "properties": { - "order": 769, - "id": 200, + "order": 1917, + "id": 199, "name": "profile", "prevSize": 32, "code": 59905 }, "setIdx": 0, - "setId": 0, - "iconIdx": 193 + "setId": 2, + "iconIdx": 200 }, { "icon": { @@ -4733,6 +5375,8 @@ "M853.331 252.235h-341.331l-85.333-81.569h-256c-46.934 0-84.907 36.706-84.907 81.569l-0.427 489.41c0 44.864 38.4 81.568 85.334 81.568h682.664c46.938 0 85.338-36.704 85.338-81.568v-407.841c0-44.863-38.4-81.569-85.338-81.569zM853.331 741.645h-682.664v-489.41h220.586l85.334 81.569h376.744v407.841zM640 537.725c46.931 0 85.331-36.706 85.331-81.569s-38.4-81.569-85.331-81.569c-46.932 0-85.332 36.706-85.332 81.569s38.4 81.569 85.332 81.569zM469.334 700.864h341.335v-40.787c0-54.242-113.92-81.568-170.669-81.568-56.746 0-170.666 27.326-170.666 81.568v40.787z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "project" ], @@ -4741,15 +5385,15 @@ }, "attrs": [], "properties": { - "order": 770, - "id": 201, + "order": 1918, + "id": 200, "name": "project", "prevSize": 32, "code": 59700 }, "setIdx": 0, - "setId": 0, - "iconIdx": 194 + "setId": 2, + "iconIdx": 201 }, { "icon": { @@ -4757,6 +5401,8 @@ "M213.333 170.667v85.333h597.333v-85.333h-597.333zM213.333 597.333h170.667v256h256v-256h170.667l-298.667-298.667-298.667 298.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "publish" ], @@ -4765,63 +5411,75 @@ }, "attrs": [], "properties": { - "order": 771, - "id": 202, + "order": 1919, + "id": 201, "name": "publish", "prevSize": 32, "code": 59906 }, "setIdx": 0, - "setId": 0, - "iconIdx": 195 + "setId": 2, + "iconIdx": 202 }, { "icon": { "paths": [ "M308.224 757.76c-9.557 0-18.944-4.78-28.16-14.336s-13.824-19.116-13.824-28.672v-100.352h512v-348.16h102.4c9.556 0 18.772 4.779 27.648 14.336s13.312 19.456 13.312 29.696v610.304l-162.816-162.816h-450.56zM102.4 716.8v-571.392c0-9.557 4.437-19.115 13.312-28.672s18.091-14.336 27.648-14.336h531.456c10.24 0 19.796 4.608 28.672 13.824s13.312 18.944 13.312 29.184v364.544c0 9.556-4.436 19.116-13.312 28.672s-18.432 14.336-28.672 14.336h-408.576l-163.84 163.84zM655.36 491.52v-327.68h-491.52v409.6l75.776-81.92h415.744z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qchat" ], "defaultCode": 59730, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 772, - "id": 203, + "order": 1920, + "id": 202, "name": "qchat", "prevSize": 32, "code": 59730 }, "setIdx": 0, - "setId": 0, - "iconIdx": 196 + "setId": 2, + "iconIdx": 203 }, { "icon": { "paths": [ "M449.536 674.816l295.936-295.936-44.032-44.032-251.904 251.904-121.856-121.856-44.032 44.032 165.888 165.888zM204.8 880.64c-16.384 0-30.72-6.144-43.008-18.432s-18.432-26.624-18.432-43.008v-614.4c0-16.384 6.144-30.72 18.432-43.008s26.624-18.432 43.008-18.432h614.4c16.384 0 30.72 6.144 43.008 18.432s18.432 26.624 18.432 43.008v614.4c0 16.384-6.144 30.72-18.432 43.008s-26.624 18.432-43.008 18.432h-614.4zM204.8 819.2h614.4v-614.4h-614.4v614.4z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qcheck" ], "defaultCode": 59732, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 773, - "id": 204, + "order": 1921, + "id": 203, "name": "qcheck", "prevSize": 32, "code": 59732 }, "setIdx": 0, - "setId": 0, - "iconIdx": 197 + "setId": 2, + "iconIdx": 204 }, { "icon": { @@ -4829,24 +5487,30 @@ "M960 821.333c0 64.802-52.531 117.333-117.333 117.333h-618.667c-64.801 0-117.333-52.531-117.333-117.333v-597.334c0-64.801 52.532-117.333 117.333-117.333h203.857c44.442 0 85.069 25.11 104.943 64.86l38.165 54.991c9.033 18.068 27.499 29.482 47.701 29.482h224c64.802 0 117.333 52.532 117.333 117.333v448zM170.667 224v202.667h725.333v-53.333c0-29.455-23.876-53.333-53.333-53.333h-224c-44.442 0-85.069-25.11-104.947-64.861l-38.161-54.991c-9.033-18.068-27.503-29.482-47.701-29.482h-203.857c-29.455 0-53.333 23.878-53.333 53.333zM170.667 490.667v330.667c0 29.457 23.878 53.333 53.333 53.333h618.667c29.457 0 53.333-23.876 53.333-53.333v-330.667h-725.333z" ], "width": 1067, - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qdocs" ], "defaultCode": 59733, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 774, - "id": 205, + "order": 1922, + "id": 204, "name": "qdocs", "prevSize": 32, "code": 59733 }, "setIdx": 0, - "setId": 0, - "iconIdx": 198 + "setId": 2, + "iconIdx": 205 }, { "icon": { @@ -4854,48 +5518,60 @@ "M533.333 896v-75.733l230.4-230.4 75.733 75.733-230.4 230.4h-75.733zM149.333 672v-64h320v64h-320zM885.333 619.733l-75.733-75.733 30.933-30.933c5.687-5.687 13.154-8.533 22.4-8.533s16.713 2.846 22.4 8.533l30.933 30.933c5.687 5.687 8.533 13.154 8.533 22.4s-2.846 16.713-8.533 22.4l-30.933 30.933zM149.333 496v-64h501.333v64h-501.333zM149.333 320v-64h501.333v64h-501.333z" ], "width": 1067, - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qforms" ], "defaultCode": 59734, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 775, - "id": 206, + "order": 1923, + "id": 205, "name": "qforms", "prevSize": 32, "code": 59734 }, "setIdx": 0, - "setId": 0, - "iconIdx": 199 + "setId": 2, + "iconIdx": 206 }, { "icon": { "paths": [ "M102.4 266.24c0-45.243 36.677-81.92 81.92-81.92h655.36c45.244 0 81.92 36.677 81.92 81.92v491.52c0 45.244-36.676 81.92-81.92 81.92h-655.36c-45.243 0-81.92-36.676-81.92-81.92v-491.52zM184.32 245.76c-11.311 0-20.48 9.169-20.48 20.48v57.814l348.16 174.081 348.16-174.080v-57.815c0-11.311-9.171-20.48-20.48-20.48h-655.36zM163.84 392.746v365.014c0 11.309 9.169 20.48 20.48 20.48h655.36c11.309 0 20.48-9.171 20.48-20.48v-365.013l-348.16 174.078-348.16-174.079z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qnote" ], "defaultCode": 59723, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 776, - "id": 207, + "order": 1924, + "id": 206, "name": "qnote", "prevSize": 32, "code": 59723 }, "setIdx": 0, - "setId": 0, - "iconIdx": 200 + "setId": 2, + "iconIdx": 207 }, { "icon": { @@ -4905,6 +5581,8 @@ "M693.333 576h-32v128l112 67.2 16-26.24-96-56.96v-112z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qnote-expired" ], @@ -4913,39 +5591,45 @@ }, "attrs": [], "properties": { - "order": 777, - "id": 208, + "order": 1925, + "id": 207, "name": "qnote-expired", "prevSize": 32, "code": 59726 }, "setIdx": 0, - "setId": 0, - "iconIdx": 201 + "setId": 2, + "iconIdx": 208 }, { "icon": { "paths": [ "M102.4 266.24c0-45.243 36.677-81.92 81.92-81.92h655.36c45.244 0 81.92 36.677 81.92 81.92v491.52c0 45.244-36.676 81.92-81.92 81.92h-655.36c-45.243 0-81.92-36.676-81.92-81.92v-491.52zM184.32 245.76c-11.311 0-20.48 9.169-20.48 20.48v57.814l348.16 174.081 348.16-174.080v-57.815c0-11.311-9.171-20.48-20.48-20.48h-655.36zM163.84 392.746v365.014c0 11.309 9.169 20.48 20.48 20.48h655.36c11.309 0 20.48-9.171 20.48-20.48v-365.013l-348.16 174.078-348.16-174.079z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qnotes" ], "defaultCode": 59735, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 778, - "id": 209, + "order": 1926, + "id": 208, "name": "qnotes", "prevSize": 32, "code": 59735 }, "setIdx": 0, - "setId": 0, - "iconIdx": 202 + "setId": 2, + "iconIdx": 209 }, { "icon": { @@ -4953,6 +5637,8 @@ "M405.333 277.333v128h-128v-128h128zM469.333 213.333h-256v256h256v-256zM405.333 618.667v128h-128v-128h128zM469.333 554.667h-256v256h256v-256zM746.667 277.333v128h-128v-128h128zM810.667 213.333h-256v256h256v-256zM554.667 554.667h64v64h-64v-64zM618.667 618.667h64v64h-64v-64zM682.667 554.667h64v64h-64v-64zM554.667 682.667h64v64h-64v-64zM618.667 746.667h64v64h-64v-64zM682.667 682.667h64v64h-64v-64zM746.667 618.667h64v64h-64v-64zM746.667 746.667h64v64h-64v-64zM938.667 298.667h-85.333v-128h-128v-85.333h213.333v213.333zM938.667 938.667v-213.333h-85.333v128h-128v85.333h213.333zM85.333 938.667h213.333v-85.333h-128v-128h-85.333v213.333zM85.333 85.333v213.333h85.333v-128h128v-85.333h-213.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qr" ], @@ -4961,15 +5647,15 @@ }, "attrs": [], "properties": { - "order": 779, - "id": 210, + "order": 1927, + "id": 209, "name": "qr", "prevSize": 32, "code": 59907 }, "setIdx": 0, - "setId": 0, - "iconIdx": 203 + "setId": 2, + "iconIdx": 210 }, { "icon": { @@ -4977,6 +5663,8 @@ "M320 64h-256v256h256v-256zM384 0v0 384h-384v-384h384zM128 128h128v128h-128zM960 64h-256v256h256v-256zM1024 0v0 384h-384v-384h384zM768 128h128v128h-128zM320 704h-256v256h256v-256zM384 640v0 384h-384v-384h384zM128 768h128v128h-128zM448 0h64v64h-64zM512 64h64v64h-64zM448 128h64v64h-64zM512 192h64v64h-64zM448 256h64v64h-64zM512 320h64v64h-64zM448 384h64v64h-64zM448 512h64v64h-64zM512 576h64v64h-64zM448 640h64v64h-64zM512 704h64v64h-64zM448 768h64v64h-64zM512 832h64v64h-64zM448 896h64v64h-64zM512 960h64v64h-64zM960 512h64v64h-64zM64 512h64v64h-64zM128 448h64v64h-64zM0 448h64v64h-64zM256 448h64v64h-64zM320 512h64v64h-64zM384 448h64v64h-64zM576 512h64v64h-64zM640 448h64v64h-64zM704 512h64v64h-64zM768 448h64v64h-64zM832 512h64v64h-64zM896 448h64v64h-64zM960 640h64v64h-64zM576 640h64v64h-64zM640 576h64v64h-64zM704 640h64v64h-64zM832 640h64v64h-64zM896 576h64v64h-64zM960 768h64v64h-64zM576 768h64v64h-64zM640 704h64v64h-64zM768 704h64v64h-64zM832 768h64v64h-64zM896 704h64v64h-64zM960 896h64v64h-64zM640 832h64v64h-64zM704 896h64v64h-64zM768 832h64v64h-64zM832 896h64v64h-64zM640 960h64v64h-64zM768 960h64v64h-64zM896 960h64v64h-64z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qrcode" ], @@ -4987,14 +5675,14 @@ "properties": { "ligatures": "qrcode", "name": "qrcode", - "order": 780, - "id": 211, + "order": 1928, + "id": 210, "prevSize": 32, "code": 59722 }, "setIdx": 0, - "setId": 0, - "iconIdx": 204 + "setId": 2, + "iconIdx": 211 }, { "icon": { @@ -5002,6 +5690,8 @@ "M64 503.842c0-242.918 196.924-439.842 439.842-439.842 242.921 0 439.844 196.924 439.844 439.842 0 242.921-196.924 439.844-439.844 439.844-242.918 0-439.842-196.924-439.842-439.844zM503.842 0c-278.263 0-503.842 225.579-503.842 503.842 0 278.266 225.579 503.844 503.842 503.844 278.266 0 503.844-225.579 503.844-503.844 0-278.263-225.579-503.842-503.844-503.842zM534.315 169.293l-28.717-58.404-114.076 232.006-254.788 37.161 184.356 180.375-43.552 254.874 228.060-120.346 228.058 120.346-43.55-254.874 184.356-180.375-254.788-37.161-85.359-173.602zM441.523 386.249l64.075-130.315 71.507 145.429 160.186 23.364-115.921 113.417 27.335 159.966-143.106-75.516-143.106 75.516 27.334-159.966-115.921-113.417 160.186-23.364 7.433-15.115z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qstar" ], @@ -5010,15 +5700,15 @@ }, "attrs": [], "properties": { - "order": 781, - "id": 212, + "order": 1929, + "id": 211, "name": "qstar", "prevSize": 32, "code": 59736 }, "setIdx": 0, - "setId": 0, - "iconIdx": 205 + "setId": 2, + "iconIdx": 212 }, { "icon": { @@ -5026,6 +5716,8 @@ "M170.667 256h-85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h597.333v-85.333h-597.333v-597.333zM853.333 85.333h-512c-46.933 0-85.333 38.4-85.333 85.333v512c0 46.933 38.4 85.333 85.333 85.333h512c46.933 0 85.333-38.4 85.333-85.333v-512c0-46.933-38.4-85.333-85.333-85.333zM810.667 469.333h-170.667v170.667h-85.333v-170.667h-170.667v-85.333h170.667v-170.667h85.333v170.667h170.667v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "queue" ], @@ -5034,39 +5726,45 @@ }, "attrs": [], "properties": { - "order": 782, - "id": 213, + "order": 1930, + "id": 212, "name": "queue", "prevSize": 32, "code": 59793 }, "setIdx": 0, - "setId": 0, - "iconIdx": 206 + "setId": 2, + "iconIdx": 213 }, { "icon": { "paths": [ "M452.608 962.56v-81.92h-247.808c-16.384 0-30.72-6.144-43.008-18.432s-18.432-26.624-18.432-43.008v-614.4c0-16.384 6.144-30.72 18.432-43.008s26.624-18.432 43.008-18.432h247.808v-81.92h61.44v901.12h-61.44zM204.8 776.192h247.808v-283.648l-247.808 283.648zM575.488 880.64v-384l243.712 279.552v-571.392h-243.712v-61.44h243.712c16.384 0 30.72 6.144 43.008 18.432s18.432 26.624 18.432 43.008v614.4c0 16.384-6.144 30.72-18.432 43.008s-26.624 18.432-43.008 18.432h-243.712z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "qvisual" ], "defaultCode": 59737, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 783, - "id": 214, + "order": 1931, + "id": 213, "name": "qvisual", "prevSize": 32, "code": 59737 }, "setIdx": 0, - "setId": 0, - "iconIdx": 207 + "setId": 2, + "iconIdx": 214 }, { "icon": { @@ -5074,6 +5772,8 @@ "M512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM512 853.333c-188.587 0-341.333-152.747-341.333-341.333s152.747-341.333 341.333-341.333c188.587 0 341.333 152.747 341.333 341.333s-152.747 341.333-341.333 341.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "radio-off" ], @@ -5082,15 +5782,15 @@ }, "attrs": [], "properties": { - "order": 784, - "id": 215, + "order": 1932, + "id": 214, "name": "radio-off", "prevSize": 32, "code": 59794 }, "setIdx": 0, - "setId": 0, - "iconIdx": 208 + "setId": 2, + "iconIdx": 215 }, { "icon": { @@ -5098,6 +5798,8 @@ "M512 298.667c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333c117.76 0 213.333-95.573 213.333-213.333s-95.573-213.333-213.333-213.333zM512 85.333c-235.52 0-426.667 191.147-426.667 426.667s191.147 426.667 426.667 426.667c235.52 0 426.667-191.147 426.667-426.667s-191.147-426.667-426.667-426.667zM512 853.333c-188.587 0-341.333-152.747-341.333-341.333s152.747-341.333 341.333-341.333c188.587 0 341.333 152.747 341.333 341.333s-152.747 341.333-341.333 341.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "radio-on" ], @@ -5106,39 +5808,45 @@ }, "attrs": [], "properties": { - "order": 785, - "id": 216, + "order": 1933, + "id": 215, "name": "radio-on", "prevSize": 32, "code": 59795 }, "setIdx": 0, - "setId": 0, - "iconIdx": 209 + "setId": 2, + "iconIdx": 216 }, { "icon": { "paths": [ "M102.4 880.64v-491.52h204.8v491.52h-204.8zM409.6 880.64v-737.28h204.8v737.28h-204.8zM716.8 880.64v-409.6h204.8v409.6h-204.8z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "rar" ], "defaultCode": 59731, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 786, - "id": 217, + "order": 1934, + "id": 216, "name": "rar", "prevSize": 32, "code": 59731 }, "setIdx": 0, - "setId": 0, - "iconIdx": 210 + "setId": 2, + "iconIdx": 217 }, { "icon": { @@ -5146,6 +5854,8 @@ "M768 384v-85.333h-85.333v-177.493c-52.48-23.040-110.080-35.84-171.093-35.84-235.52 0-426.24 191.147-426.24 426.667s190.72 426.667 426.24 426.667c235.947 0 427.093-191.147 427.093-426.667 0-44.8-7.253-87.467-20.053-128h-150.613zM661.333 341.333c35.413 0 64 28.587 64 64s-28.587 64-64 64c-35.413 0-64-28.587-64-64s28.587-64 64-64zM362.667 341.333c35.413 0 64 28.587 64 64s-28.587 64-64 64c-35.413 0-64-28.587-64-64s28.587-64 64-64zM512 746.667c-99.413 0-183.893-62.293-218.027-149.333h436.053c-34.133 87.040-118.613 149.333-218.027 149.333zM938.667 128h85.333v85.333h-85.333v85.333h-85.333v-85.333h-85.333v-85.333h85.333v-85.333h85.333v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "react-add" ], @@ -5154,15 +5864,15 @@ }, "attrs": [], "properties": { - "order": 787, - "id": 218, + "order": 1935, + "id": 217, "name": "react-add", "prevSize": 32, "code": 59908 }, "setIdx": 0, - "setId": 0, - "iconIdx": 211 + "setId": 2, + "iconIdx": 218 }, { "icon": { @@ -5170,6 +5880,8 @@ "M512 85.333c-235.699 0-426.667 190.968-426.667 426.667s190.968 426.667 426.667 426.667c235.699 0 426.667-190.967 426.667-426.667s-190.967-426.667-426.667-426.667zM512 856.085c-189.763 0-344.086-154.321-344.086-344.085s154.323-344.086 344.086-344.086c189.764 0 344.085 154.323 344.085 344.086s-154.321 344.085-344.085 344.085zM512 608.346c-57.805 0-112.172 25.459-149.333 69.85-14.624 17.549-12.215 43.524 5.333 58.15 17.548 14.622 43.527 12.386 58.15-5.163 42.667-51.098 129.033-51.098 171.699 0 13.935 16.687 39.915 20.471 58.15 5.163 17.549-14.626 19.785-40.602 5.333-58.15-37.163-44.39-91.529-69.85-149.333-69.85zM429.419 484.471c17.719 0 34.236-11.524 39.569-29.419 6.541-21.85-5.85-44.902-27.699-51.44l-137.632-41.29c-22.022-6.71-44.903 5.849-51.441 27.699s5.85 44.901 27.699 51.442l48.516 14.622c-5.333 8.431-9.118 17.894-9.118 28.561 0 30.451 24.602 55.053 55.054 55.053s55.053-24.777 55.053-55.228zM771.785 390.022c-6.537-21.85-29.419-34.237-51.439-27.699l-137.634 41.29c-21.85 6.537-34.24 29.59-27.699 51.44 5.333 17.894 21.85 29.419 39.569 29.419 0 30.451 24.602 55.057 55.053 55.057s55.053-24.606 55.053-55.057c0-10.667-3.785-20.126-9.118-28.557l48.516-14.626c21.85-6.366 34.236-29.417 27.699-51.267z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "react-angry" ], @@ -5178,15 +5890,15 @@ }, "attrs": [], "properties": { - "order": 788, - "id": 219, + "order": 1936, + "id": 218, "name": "react-angry", "prevSize": 32, "code": 59909 }, "setIdx": 0, - "setId": 0, - "iconIdx": 212 + "setId": 2, + "iconIdx": 219 }, { "icon": { @@ -5194,6 +5906,8 @@ "M870.071 465.967c13.154 22.272 20.595 46.033 20.595 74.756 0 66.022-55.825 128.371-128.73 128.371h-54.72c7.381 19.217 13.274 42.197 13.274 69.811 0 109.188-56.533 157.094-142.903 157.094-92.412 0-87.138-142.4-107.639-162.901-34.121-34.121-74.423-99.669-103.141-125.099h-148.14c-26.51 0-48-21.491-48-48v-360c0-26.51 21.49-48 48-48h96c22.339 0 41.112 15.261 46.467 35.925 66.762-1.501 112.59-59.91 266.702-59.91 10.833 0 22.831-0.015 33.331-0.015 115.674 0 167.979 59.134 169.408 142.995 19.981 27.637 30.451 64.683 26.014 100.485 14.78 27.678 20.493 60.516 13.483 94.487zM777.446 385.22c18.842-31.695 1.89-74.115-20.911-86.355 11.55-73.17-26.411-98.85-79.68-98.85h-56.73c-107.456 0-177.041 56.73-257.459 56.73v279.255h16.38c42.54 0 101.969 106.334 141.811 146.189 42.539 42.543 28.365 113.446 56.73 141.811 70.903 0 70.903-49.472 70.903-85.094 0-58.756-42.539-85.082-42.539-141.811h155.985c31.663 0 56.593-28.365 56.73-56.73 0.137-28.348-19.23-56.717-33.404-56.717 20.233-21.833 24.555-67.852-7.817-98.428zM302.667 248c0-19.883-16.117-36-36-36s-36 16.117-36 36c0 19.883 16.117 36 36 36s36-16.117 36-36z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "react-thumbsdown" ], @@ -5202,15 +5916,15 @@ }, "attrs": [], "properties": { - "order": 789, - "id": 220, + "order": 1937, + "id": 219, "name": "react-thumbsdown", "prevSize": 32, "code": 59910 }, "setIdx": 0, - "setId": 0, - "iconIdx": 213 + "setId": 2, + "iconIdx": 220 }, { "icon": { @@ -5218,6 +5932,8 @@ "M870.071 558.033c13.154-22.272 20.595-46.033 20.595-74.756 0-66.024-55.825-128.372-128.73-128.372h-54.72c7.381-19.215 13.274-42.195 13.274-69.81 0-109.191-56.533-157.095-142.903-157.095-92.412 0-87.138 142.4-107.639 162.9-34.121 34.121-74.423 99.671-103.141 125.1h-148.14c-26.51 0-48 21.491-48 48v360c0 26.509 21.49 48 48 48h96c22.339 0 41.112-15.262 46.467-35.925 66.762 1.502 112.59 59.908 266.702 59.908 10.833 0 22.831 0.017 33.331 0.017 115.674 0 167.979-59.136 169.408-142.993 19.981-27.639 30.451-64.687 26.014-100.489 14.78-27.678 20.493-60.514 13.483-94.485zM777.446 638.78c18.842 31.697 1.89 74.116-20.911 86.357 11.55 73.169-26.411 98.846-79.68 98.846h-56.73c-107.456 0-177.041-56.73-257.459-56.73v-279.253h16.38c42.54 0 101.969-106.335 141.811-146.19 42.539-42.54 28.365-113.445 56.73-141.81 70.903 0 70.903 49.47 70.903 85.095 0 58.755-42.539 85.080-42.539 141.811h155.985c31.663 0 56.593 28.365 56.73 56.73 0.137 28.348-19.23 56.717-33.404 56.717 20.233 21.833 24.555 67.853-7.817 98.428zM302.667 776c0 19.883-16.117 35.998-36 35.998s-36-16.115-36-35.998c0-19.883 16.117-35.998 36-35.998s36 16.115 36 35.998z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "react-thumbsup" ], @@ -5226,15 +5942,15 @@ }, "attrs": [], "properties": { - "order": 790, - "id": 221, + "order": 1938, + "id": 220, "name": "react-thumbsup", "prevSize": 32, "code": 59911 }, "setIdx": 0, - "setId": 0, - "iconIdx": 214 + "setId": 2, + "iconIdx": 221 }, { "icon": { @@ -5242,6 +5958,8 @@ "M810.667 128h-178.347c-17.92-49.493-64.853-85.333-120.32-85.333s-102.4 35.84-120.32 85.333h-178.347c-46.933 0-85.333 38.4-85.333 85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333zM512 117.333c9.387 0 17.493 4.267 23.467 10.667 5.12 5.547 8.533 13.227 8.533 21.333 0 17.493-14.507 32-32 32s-32-14.507-32-32c0-8.107 3.413-15.787 8.533-21.333 5.973-6.4 14.080-10.667 23.467-10.667zM810.667 810.667h-597.333v-597.333h597.333v597.333zM512 256c-70.4 0-128 57.6-128 128s57.6 128 128 128c70.4 0 128-57.6 128-128s-57.6-128-128-128zM512 426.667c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667zM256 702.72v65.28h512v-65.28c0-106.667-169.387-152.747-256-152.747s-256 45.653-256 152.747zM354.56 682.667c29.44-23.893 101.547-47.787 157.44-47.787s128.427 23.893 157.44 47.787h-314.88z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "reassign" ], @@ -5250,15 +5968,15 @@ }, "attrs": [], "properties": { - "order": 791, - "id": 222, + "order": 1939, + "id": 221, "name": "reassign", "prevSize": 32, "code": 59719 }, "setIdx": 0, - "setId": 0, - "iconIdx": 215 + "setId": 2, + "iconIdx": 222 }, { "icon": { @@ -5266,6 +5984,8 @@ "M810.667 298.667v170.667h-561.92l152.747-153.173-60.16-60.16-256 256 256 256 60.16-60.16-152.747-153.173h647.253v-256h-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "recall" ], @@ -5274,39 +5994,15 @@ }, "attrs": [], "properties": { - "order": 792, - "id": 223, + "order": 1940, + "id": 222, "name": "recall", "prevSize": 32, "code": 59796 }, "setIdx": 0, - "setId": 0, - "iconIdx": 216 - }, - { - "icon": { - "paths": [ - "M448 298.667c-73.553 0-144.094 29.219-196.104 81.229s-81.229 122.551-81.229 196.104c0 73.553 29.219 144.094 81.229 196.105s122.551 81.229 196.104 81.229h149.333v-85.333h-149.333c-106.667 0-192-85.333-192-192s85.333-192 192-192h241.92l-131.413 131.84 60.16 60.16 234.667-234.667-234.667-234.667-60.587 60.16 131.84 131.84h-241.92zM768 768h-85.333v85.333h85.333v-85.333z" - ], - "attrs": [], - "tags": [ - "mdi-redo-variant" - ], - "defaultCode": 59685, - "grid": 16 - }, - "attrs": [], - "properties": { - "order": 719, - "id": 150, - "name": "redo-variant", - "prevSize": 32, - "code": 59685 - }, - "setIdx": 0, - "setId": 0, - "iconIdx": 217 + "setId": 2, + "iconIdx": 223 }, { "icon": { @@ -5314,6 +6010,8 @@ "M753.067 270.933c-61.867-61.867-146.773-100.267-241.067-100.267-188.586 0-340.906 152.747-340.906 341.333s152.32 341.333 340.906 341.333c159.147 0 291.84-108.8 329.813-256h-88.747c-34.987 99.413-129.707 170.667-241.067 170.667-141.226 0-256-114.773-256-256s114.773-256 256-256c70.827 0 133.973 29.44 180.053 75.947l-137.387 137.387h298.667v-298.667l-100.267 100.267z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "refresh" ], @@ -5322,15 +6020,15 @@ }, "attrs": [], "properties": { - "order": 793, - "id": 224, + "order": 1941, + "id": 223, "name": "refresh", "prevSize": 32, "code": 59797 }, "setIdx": 0, - "setId": 0, - "iconIdx": 218 + "setId": 2, + "iconIdx": 224 }, { "icon": { @@ -5339,6 +6037,8 @@ "M646.912 341.334c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM646.912 426.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333zM646.912 682.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "reorder" ], @@ -5347,15 +6047,15 @@ }, "attrs": [], "properties": { - "order": 794, - "id": 225, + "order": 1942, + "id": 224, "name": "reorder", "prevSize": 32, "code": 59798 }, "setIdx": 0, - "setId": 0, - "iconIdx": 219 + "setId": 2, + "iconIdx": 225 }, { "icon": { @@ -5363,6 +6063,8 @@ "M298.667 298.667h426.667v128l170.667-170.667-170.667-170.667v128h-512v256h85.333v-170.667zM725.333 725.333h-426.667v-128l-170.667 170.667 170.667 170.667v-128h512v-256h-85.333v170.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "repeat" ], @@ -5371,15 +6073,15 @@ }, "attrs": [], "properties": { - "order": 795, - "id": 226, + "order": 1943, + "id": 225, "name": "repeat", "prevSize": 32, "code": 59799 }, "setIdx": 0, - "setId": 0, - "iconIdx": 220 + "setId": 2, + "iconIdx": 226 }, { "icon": { @@ -5387,6 +6089,8 @@ "M213.333 128h597.333c46.933 0 85.333 38.4 85.333 85.333v597.333c0 46.933-38.4 85.333-85.333 85.333h-597.333c-46.933 0-85.333-38.4-85.333-85.333v-597.333c0-46.933 38.4-85.333 85.333-85.333zM213.333 810.667h597.333v-597.333h-597.333v597.333zM384 512h-85.333v213.333h85.333v-213.333zM725.333 298.667h-85.333v426.667h85.333v-426.667zM554.667 597.333h-85.333v128h85.333v-128zM554.667 426.667h-85.333v85.333h85.333v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "report" ], @@ -5395,15 +6099,15 @@ }, "attrs": [], "properties": { - "order": 796, - "id": 227, + "order": 1944, + "id": 226, "name": "report", "prevSize": 32, "code": 59701 }, "setIdx": 0, - "setId": 0, - "iconIdx": 221 + "setId": 2, + "iconIdx": 227 }, { "icon": { @@ -5412,6 +6116,8 @@ "M256 554.667c0-70.4 28.587-134.4 75.093-180.907l-60.587-60.587c-61.44 61.867-99.84 147.2-99.84 241.493 0 174.080 130.133 317.44 298.667 338.347v-86.187c-120.747-20.48-213.333-125.44-213.333-252.16z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "reset" ], @@ -5420,15 +6126,15 @@ }, "attrs": [], "properties": { - "order": 797, - "id": 228, + "order": 1945, + "id": 227, "name": "reset", "prevSize": 32, "code": 59800 }, "setIdx": 0, - "setId": 0, - "iconIdx": 222 + "setId": 2, + "iconIdx": 228 }, { "icon": { @@ -5436,6 +6142,8 @@ "M853.333 85.333h-682.667c-46.933 0-84.907 38.4-84.907 85.333l-0.427 768 170.667-170.667h597.333c46.933 0 85.333-38.4 85.333-85.333v-512c0-46.933-38.4-85.333-85.333-85.333zM853.333 682.667h-632.747l-49.92 49.92v-561.92h682.667v512zM448 597.333h320v-85.333h-234.667l-85.333 85.333zM612.693 346.88c8.533-8.533 8.533-21.76 0-30.293l-75.52-75.52c-8.533-8.533-21.76-8.533-30.293 0l-250.88 250.88v105.387h105.387l251.307-250.453z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "review" ], @@ -5444,15 +6152,15 @@ }, "attrs": [], "properties": { - "order": 798, - "id": 229, + "order": 1946, + "id": 228, "name": "review", "prevSize": 32, "code": 59702 }, "setIdx": 0, - "setId": 0, - "iconIdx": 223 + "setId": 2, + "iconIdx": 229 }, { "icon": { @@ -5460,6 +6168,8 @@ "M562.684 484.868l-83.452-23.834c-2.931-0.845-5.513-2.62-7.356-5.056-1.839-2.441-2.837-5.41-2.842-8.461 0-7.735 6.298-14.033 14.067-14.033h54.63c5.999 0 11.802 1.28 17.101 3.699 8 3.682 17.284 2.85 23.518-3.383l29.201-29.201c8.781-8.783 7.782-23.8-2.586-30.633-15.834-10.45-33.916-16.85-52.966-19.1v-29.533c0-14.733-11.934-26.667-26.667-26.667h-26.667c-14.733 0-26.667 11.933-26.667 26.667v29.267c-50.483 6.033-88.95 51.633-82.2 105.082 4.833 38.251 34.433 68.851 71.516 79.45l83.452 23.834c2.931 0.845 5.513 2.62 7.356 5.056 1.839 2.441 2.837 5.41 2.842 8.461 0 7.735-6.298 14.033-14.067 14.033h-54.63c-5.999 0-11.802-1.28-17.101-3.699-8-3.682-17.284-2.85-23.518 3.383l-29.199 29.201c-8.783 8.781-7.784 23.799 2.583 30.635 15.834 10.449 33.916 16.849 52.967 19.098v29.534c0 14.733 11.934 26.667 26.667 26.667h26.667c14.733 0 26.667-11.934 26.667-26.667v-29.265c50.483-6.033 88.951-51.635 82.202-105.084-4.834-38.251-34.436-68.851-71.518-79.45zM938.667 512c0-60.834-31.334-114-77.833-144.5 11.332-54.833-4.501-114.5-47.168-157.167-42.667-42.833-102.498-58.5-157.167-47.167-30.831-46.667-83.998-77.833-144.499-77.833s-113.833 31.167-144.5 77.833c-54.833-11.334-114.5 4.5-157.167 47.167-42.833 42.667-58.5 102.5-47.167 157.167-46.833 30.833-77.833 84.165-77.833 144.5 0 60.501 31.167 113.835 77.833 144.499-11.334 54.835 4.5 114.5 47.167 157.167 42.667 42.833 102 58.5 157.167 47.168 30.833 46.831 84.165 77.833 144.5 77.833 60.668 0 113.835-31.334 144.499-77.833 55.168 11.332 114.5-4.501 157.167-47.168 42.833-42.667 58.5-102.498 47.168-157.167 46.831-30.831 77.833-84.164 77.833-144.499zM758.165 614.165c15.168 33.169 50.5 91.337-1.165 143.002-46.669 46.665-92.169 24.166-143.002 1.165-12.834 34.334-28.834 100.335-101.999 100.335-75.499 0-91.167-71.334-102-100.335-35.167 16-91.5 50.334-143.167-1.331-53.333-53.333-14-114.833-1.167-143.002-34.333-12.834-100.333-28.834-100.333-101.999 0-75.499 71.334-91.167 100.5-102.167-15.167-33.167-50.5-91.334 1.167-143 53.333-53.333 114.833-14 143-1.167 12.833-34.333 28.835-100.333 102-100.333 75.499 0 91.166 71.334 101.999 100.667 33.169-15.167 91.332-50.5 143.002 1.167 53.333 53.333 13.999 114.833 1.165 143 34.334 12.833 100.335 28.835 100.335 102 0 75.499-71.334 91.166-100.335 101.999z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "sales" ], @@ -5468,15 +6178,15 @@ }, "attrs": [], "properties": { - "order": 799, - "id": 230, + "order": 1947, + "id": 229, "name": "sales", "prevSize": 32, "code": 59703 }, "setIdx": 0, - "setId": 0, - "iconIdx": 224 + "setId": 2, + "iconIdx": 230 }, { "icon": { @@ -5484,6 +6194,8 @@ "M725.333 128h-512c-47.36 0-85.333 38.4-85.333 85.333v597.333c0 46.933 37.973 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-512l-170.667-170.667zM512 810.667c-70.827 0-128-57.173-128-128s57.173-128 128-128c70.827 0 128 57.173 128 128s-57.173 128-128 128zM640 384h-426.667v-170.667h426.667v170.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "save" ], @@ -5492,15 +6204,15 @@ }, "attrs": [], "properties": { - "order": 800, - "id": 231, + "order": 1948, + "id": 230, "name": "save", "prevSize": 32, "code": 59912 }, "setIdx": 0, - "setId": 0, - "iconIdx": 225 + "setId": 2, + "iconIdx": 231 }, { "icon": { @@ -5509,6 +6221,8 @@ "M533.334 298.666h-64v256l223.997 134.403 32-52.483-191.997-113.92v-224z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "schedule" ], @@ -5517,15 +6231,15 @@ }, "attrs": [], "properties": { - "order": 801, - "id": 232, + "order": 1949, + "id": 231, "name": "schedule", "prevSize": 32, "code": 59704 }, "setIdx": 0, - "setId": 0, - "iconIdx": 226 + "setId": 2, + "iconIdx": 232 }, { "icon": { @@ -5533,23 +6247,29 @@ "M196.923 905.846c-15.754 0-29.538-5.908-41.354-17.723s-17.723-25.6-17.723-41.354v-610.462c0-15.754 5.908-29.538 17.723-41.354s25.6-17.723 41.354-17.723h64v-59.077h64v59.077h334.769v-59.077h64v59.077h64c15.754 0 29.538 5.908 41.354 17.723s17.723 25.6 17.723 41.354v610.462c0 15.754-5.908 29.538-17.723 41.354s-25.6 17.723-41.354 17.723h-590.769zM196.923 846.769h590.769v-423.385h-590.769v423.385z" ], "width": 985, - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "scheduling" ], "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 802, - "id": 233, + "order": 1950, + "id": 232, "name": "scheduling", "prevSize": 32, "code": 59806 }, "setIdx": 0, - "setId": 0, - "iconIdx": 227 + "setId": 2, + "iconIdx": 233 }, { "icon": { @@ -5557,6 +6277,8 @@ "M661.333 597.333h-33.707l-11.947-11.52c41.813-48.64 66.987-111.787 66.987-180.48 0-153.173-124.16-277.333-277.333-277.333s-277.333 124.16-277.333 277.333c0 153.173 124.16 277.333 277.333 277.333 68.693 0 131.84-25.173 180.48-66.987l11.52 11.947v33.707l213.333 212.907 63.573-63.573-212.907-213.333zM405.333 597.333c-106.24 0-192-85.76-192-192s85.76-192 192-192c106.24 0 192 85.76 192 192s-85.76 192-192 192z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "search" ], @@ -5565,15 +6287,15 @@ }, "attrs": [], "properties": { - "order": 803, - "id": 234, + "order": 1951, + "id": 233, "name": "search", "prevSize": 32, "code": 59705 }, "setIdx": 0, - "setId": 0, - "iconIdx": 228 + "setId": 2, + "iconIdx": 234 }, { "icon": { @@ -5581,6 +6303,8 @@ "M298.667 384h-213.333v-85.333h213.333v85.333zM298.667 512h-213.333v85.333h213.333v-85.333zM878.507 810.667l-163.413-163.413c-34.133 22.187-74.24 35.413-117.76 35.413-117.76 0-213.333-95.573-213.333-213.333s95.573-213.333 213.333-213.333c117.76 0 213.333 95.573 213.333 213.333 0 43.52-13.227 83.627-35.413 117.333l163.413 163.84-60.16 60.16zM725.333 469.333c0-70.4-57.6-128-128-128s-128 57.6-128 128c0 70.4 57.6 128 128 128s128-57.6 128-128zM85.333 810.667h426.667v-85.333h-426.667v85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "search-advance" ], @@ -5589,39 +6313,44 @@ }, "attrs": [], "properties": { - "order": 804, - "id": 235, + "order": 1952, + "id": 234, "name": "search-advance", "prevSize": 32, "code": 59721 }, "setIdx": 0, - "setId": 0, - "iconIdx": 229 + "setId": 2, + "iconIdx": 235 }, { "icon": { "paths": [ - "M512 42.667l-384 170.667v256c0 236.8 163.84 458.24 384 512 220.16-53.76 384-275.2 384-512v-256l-384-170.667zM512 511.573h298.667c-22.613 175.787-139.947 332.373-298.667 381.44v-381.013h-298.667v-243.2l298.667-132.693v375.467z" + "M512.182 128l-314.182 139.636v209.456c0 193.744 134.050 374.922 314.182 418.908 180.13-43.986 314.182-225.164 314.182-418.908v-209.456l-314.182-139.636zM512.182 511.65h244.364c-18.502 143.826-114.502 271.942-244.364 312.088v-311.738h-244.364v-198.982l244.364-108.568v307.2z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "security" ], - "grid": 16, - "defaultCode": 59812 + "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 567, - "id": 280, + "order": 1953, + "id": 235, "name": "security", "prevSize": 32, - "code": 59812 + "code": 59694 }, "setIdx": 0, - "setId": 0, - "iconIdx": 230 + "setId": 2, + "iconIdx": 236 }, { "icon": { @@ -5629,6 +6358,8 @@ "M85.76 896l895.573-384-895.573-384-0.427 298.667 640 85.333-640 85.333 0.427 298.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "send" ], @@ -5637,15 +6368,15 @@ }, "attrs": [], "properties": { - "order": 805, + "order": 1954, "id": 236, "name": "send", "prevSize": 32, "code": 59706 }, "setIdx": 0, - "setId": 0, - "iconIdx": 231 + "setId": 2, + "iconIdx": 237 }, { "icon": { @@ -5653,6 +6384,8 @@ "M816.64 551.936c1.536-12.8 2.56-26.112 2.56-39.936s-1.024-27.136-3.072-39.936l86.528-67.584c7.68-6.144 9.728-17.408 5.12-26.112l-81.92-141.824c-5.12-9.216-15.872-12.288-25.088-9.216l-101.888 40.96c-21.504-16.384-44.032-29.696-69.12-39.936l-15.36-108.544c-1.536-10.24-10.24-17.408-20.48-17.408h-163.84c-10.241 0-18.432 7.168-19.968 17.408l-15.36 108.544c-25.088 10.24-48.128 24.064-69.12 39.936l-101.888-40.96c-9.216-3.584-19.968 0-25.088 9.216l-81.92 141.824c-5.12 9.216-3.072 19.968 5.12 26.112l86.528 67.584c-2.048 12.8-3.584 26.624-3.584 39.936s1.024 27.136 3.072 39.936l-86.528 67.584c-7.68 6.144-9.728 17.408-5.12 26.112l81.92 141.824c5.12 9.216 15.872 12.288 25.088 9.216l101.888-40.96c21.504 16.384 44.032 29.696 69.12 39.936l15.36 108.544c2.048 10.24 10.24 17.408 20.48 17.408h163.84c10.24 0 18.944-7.168 19.968-17.408l15.36-108.544c25.088-10.24 48.128-24.064 69.12-39.936l101.888 40.96c9.216 3.584 19.968 0 25.088-9.216l81.92-141.824c5.12-9.216 3.072-19.968-5.12-26.112l-85.504-67.584zM512 665.6c-84.48 0-153.601-69.12-153.601-153.6s69.121-153.6 153.601-153.6c84.48 0 153.6 69.12 153.6 153.6s-69.12 153.6-153.6 153.6z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "settings-gear" ], @@ -5661,15 +6394,15 @@ }, "attrs": [], "properties": { - "order": 806, + "order": 1955, "id": 237, "name": "settings-gear", "prevSize": 32, "code": 59803 }, "setIdx": 0, - "setId": 0, - "iconIdx": 232 + "setId": 2, + "iconIdx": 238 }, { "icon": { @@ -5677,6 +6410,8 @@ "M128 725.333v85.333h256v-85.333h-256zM128 213.333v85.333h426.667v-85.333h-426.667zM554.667 896v-85.333h341.333v-85.333h-341.333v-85.333h-85.333v256h85.333zM298.667 384v85.333h-170.667v85.333h170.667v85.333h85.333v-256h-85.333zM896 554.667v-85.333h-426.667v85.333h426.667zM640 384h85.333v-85.333h170.667v-85.333h-170.667v-85.333h-85.333v256z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "settings-tune" ], @@ -5685,15 +6420,15 @@ }, "attrs": [], "properties": { - "order": 807, + "order": 1956, "id": 238, "name": "settings-tune", "prevSize": 32, "code": 59804 }, "setIdx": 0, - "setId": 0, - "iconIdx": 233 + "setId": 2, + "iconIdx": 239 }, { "icon": { @@ -5701,6 +6436,8 @@ "M768 686.080c-32.427 0-61.44 12.8-83.627 32.853l-304.213-177.067c2.133-9.813 3.84-19.627 3.84-29.867s-1.707-20.053-3.84-29.867l300.8-175.36c23.040 21.333 53.333 34.56 87.040 34.56 70.827 0 128-57.173 128-128s-57.173-128-128-128c-70.827 0-128 57.173-128 128 0 10.24 1.707 20.053 3.84 29.867l-300.8 175.36c-23.040-21.333-53.333-34.56-87.040-34.56-70.827 0-128 57.173-128 128s57.173 128 128 128c33.707 0 64-13.227 87.040-34.56l303.787 177.493c-2.133 8.96-3.413 18.347-3.413 27.733 0 68.693 55.893 124.587 124.587 124.587s124.587-55.893 124.587-124.587c0-68.693-55.893-124.587-124.587-124.587z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "share" ], @@ -5709,15 +6446,15 @@ }, "attrs": [], "properties": { - "order": 808, + "order": 1957, "id": 239, "name": "share", "prevSize": 32, "code": 59915 }, "setIdx": 0, - "setId": 0, - "iconIdx": 234 + "setId": 2, + "iconIdx": 240 }, { "icon": { @@ -5725,6 +6462,8 @@ "M682.667 213.333l-60.587 60.587-67.84-67.84v476.587h-84.48v-476.587l-67.84 67.84-60.587-60.587 170.667-170.667 170.667 170.667zM853.333 426.667v469.333c0 46.933-38.4 85.333-85.333 85.333h-512c-47.36 0-85.333-38.4-85.333-85.333v-469.333c0-47.36 37.973-85.333 85.333-85.333h128v85.333h-128v469.333h512v-469.333h-128v-85.333h128c46.933 0 85.333 37.973 85.333 85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "share-file" ], @@ -5733,15 +6472,15 @@ }, "attrs": [], "properties": { - "order": 809, + "order": 1958, "id": 240, "name": "share-file", "prevSize": 32, "code": 59914 }, "setIdx": 0, - "setId": 0, - "iconIdx": 235 + "setId": 2, + "iconIdx": 241 }, { "icon": { @@ -5749,6 +6488,8 @@ "M725.333 341.333l-60.16 60.16 67.413 67.84h-348.587v85.333h348.587l-67.413 67.413 60.16 60.587 170.667-170.667-170.667-170.667zM213.333 213.333h298.667v-85.333h-298.667c-46.933 0-85.333 38.4-85.333 85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h298.667v-85.333h-298.667v-597.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "sign out" ], @@ -5757,15 +6498,15 @@ }, "attrs": [], "properties": { - "order": 810, + "order": 1959, "id": 241, "name": "sign-out", "prevSize": 32, "code": 59707 }, "setIdx": 0, - "setId": 0, - "iconIdx": 236 + "setId": 2, + "iconIdx": 242 }, { "icon": { @@ -5774,24 +6515,34 @@ "M539.443 553.779c-9.011-0.41-18.022-0.819-27.443-0.819-99.123 0-191.693 27.443-270.746 74.547-36.045 21.299-56.934 61.44-56.934 103.629v169.984h379.29c-32.358-46.285-51.61-164.25-51.61-225.28 0-43.827 10.24-84.787 27.443-122.061z", "M707.49 534.344l-134.050 100.536v48.411c0 82.661 57.197 159.965 134.050 178.733 76.857-18.768 134.054-96.072 134.054-178.733v-48.411l-134.054-100.536z" ], - "attrs": [], + "attrs": [ + {}, + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "sm" ], "defaultCode": 59739, "grid": 16 }, - "attrs": [], + "attrs": [ + {}, + {}, + {} + ], "properties": { - "order": 811, + "order": 1960, "id": 242, "name": "sm", "prevSize": 32, "code": 59739 }, "setIdx": 0, - "setId": 0, - "iconIdx": 237 + "setId": 2, + "iconIdx": 243 }, { "icon": { @@ -5802,6 +6553,8 @@ "M320 192h192v64h-192v-64z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "sort" ], @@ -5810,15 +6563,15 @@ }, "attrs": [], "properties": { - "order": 812, + "order": 1961, "id": 243, "name": "sort", "prevSize": 32, "code": 59708 }, "setIdx": 0, - "setId": 0, - "iconIdx": 238 + "setId": 2, + "iconIdx": 244 }, { "icon": { @@ -5826,6 +6579,8 @@ "M480 64c-265.096 0-480 214.904-480 480 0 265.098 214.904 480 480 480 265.098 0 480-214.902 480-480 0-265.096-214.902-480-480-480zM751.59 704c8.58-40.454 13.996-83.392 15.758-128h127.446c-3.336 44.196-13.624 87.114-30.68 128h-112.524zM208.41 384c-8.58 40.454-13.996 83.392-15.758 128h-127.444c3.336-44.194 13.622-87.114 30.678-128h112.524zM686.036 384c9.614 40.962 15.398 83.854 17.28 128h-191.316v-128h174.036zM512 320v-187.338c14.59 4.246 29.044 11.37 43.228 21.37 26.582 18.74 52.012 47.608 73.54 83.486 14.882 24.802 27.752 52.416 38.496 82.484h-155.264zM331.232 237.516c21.528-35.878 46.956-64.748 73.54-83.486 14.182-10 28.638-17.124 43.228-21.37v187.34h-155.264c10.746-30.066 23.616-57.68 38.496-82.484zM448 384v128h-191.314c1.88-44.146 7.666-87.038 17.278-128h174.036zM95.888 704c-17.056-40.886-27.342-83.804-30.678-128h127.444c1.762 44.608 7.178 87.546 15.758 128h-112.524zM256.686 576h191.314v128h-174.036c-9.612-40.96-15.398-83.854-17.278-128zM448 768v187.34c-14.588-4.246-29.044-11.372-43.228-21.37-26.584-18.74-52.014-47.61-73.54-83.486-14.882-24.804-27.75-52.418-38.498-82.484h155.266zM628.768 850.484c-21.528 35.876-46.958 64.746-73.54 83.486-14.184 9.998-28.638 17.124-43.228 21.37v-187.34h155.266c-10.746 30.066-23.616 57.68-38.498 82.484zM512 704v-128h191.314c-1.88 44.146-7.666 87.040-17.28 128h-174.034zM767.348 512c-1.762-44.608-7.178-87.546-15.758-128h112.524c17.056 40.886 27.344 83.806 30.68 128h-127.446zM830.658 320h-95.9c-18.638-58.762-44.376-110.294-75.316-151.428 42.536 20.34 81.058 47.616 114.714 81.272 21.48 21.478 40.362 44.938 56.502 70.156zM185.844 249.844c33.658-33.658 72.18-60.932 114.714-81.272-30.942 41.134-56.676 92.666-75.316 151.428h-95.898c16.138-25.218 35.022-48.678 56.5-70.156zM129.344 768h95.898c18.64 58.762 44.376 110.294 75.318 151.43-42.536-20.34-81.058-47.616-114.714-81.274-21.48-21.478-40.364-44.938-56.502-70.156zM774.156 838.156c-33.656 33.658-72.18 60.934-114.714 81.274 30.942-41.134 56.678-92.668 75.316-151.43h95.9c-16.14 25.218-35.022 48.678-56.502 70.156z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "sphere", "globe", @@ -5838,14 +6593,14 @@ "properties": { "ligatures": "sphere, globe", "name": "sphere", - "order": 813, + "order": 1962, "id": 244, "prevSize": 32, "code": 59849 }, "setIdx": 0, - "setId": 0, - "iconIdx": 239 + "setId": 2, + "iconIdx": 245 }, { "icon": { @@ -5853,6 +6608,8 @@ "M511.995 736.851l263.679 159.142-69.971-299.946 232.96-201.813-306.774-26.027-119.893-282.88-119.893 282.88-306.774 26.027 232.96 201.813-69.973 299.946 263.68-159.142z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "star" ], @@ -5861,15 +6618,15 @@ }, "attrs": [], "properties": { - "order": 814, + "order": 1963, "id": 245, "name": "star", "prevSize": 32, "code": 59709 }, "setIdx": 0, - "setId": 0, - "iconIdx": 240 + "setId": 2, + "iconIdx": 246 }, { "icon": { @@ -5877,6 +6634,8 @@ "M512 687.019l199.155 120.201-52.851-226.551 175.991-152.461-231.646-19.655-90.65-213.881-90.65 213.881-231.647 19.655 175.992 152.461-52.852 226.551 199.157-120.201zM248.32 896l69.973-299.947-232.96-201.813 306.773-26.027 119.893-282.88 119.893 282.88 306.773 26.027-232.96 201.813 69.973 299.947-263.68-159.147-263.68 159.147z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "start-outlined" ], @@ -5885,15 +6644,15 @@ }, "attrs": [], "properties": { - "order": 815, + "order": 1964, "id": 246, "name": "start-outlined", "prevSize": 32, "code": 59718 }, "setIdx": 0, - "setId": 0, - "iconIdx": 241 + "setId": 2, + "iconIdx": 247 }, { "icon": { @@ -5901,6 +6660,8 @@ "M853.333 170.667h-682.667v85.333h682.667v-85.333zM896 597.333v-85.333l-42.667-213.333h-682.667l-42.667 213.333v85.333h42.667v256h426.667v-256h170.667v256h85.333v-256h42.667zM512 768h-256v-170.667h256v170.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "store" ], @@ -5909,15 +6670,15 @@ }, "attrs": [], "properties": { - "order": 816, + "order": 1965, "id": 247, "name": "store", "prevSize": 32, "code": 59917 }, "setIdx": 0, - "setId": 0, - "iconIdx": 242 + "setId": 2, + "iconIdx": 248 }, { "icon": { @@ -5926,6 +6687,8 @@ "M768 618.667v-64l-85.333 85.333 85.333 85.333v-64c70.613 0 128 57.387 128 128 0 21.547-5.333 42.027-14.933 59.733l31.147 31.147c16.64-26.24 26.453-57.387 26.453-90.88 0-94.293-76.373-170.667-170.667-170.667zM768 917.333c-70.613 0-128-57.387-128-128 0-21.547 5.333-42.027 14.933-59.733l-31.147-31.147c-16.64 26.24-26.453 57.387-26.453 90.88 0 94.293 76.373 170.667 170.667 170.667v64l85.333-85.333-85.333-85.333v64z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "store-swap" ], @@ -5934,63 +6697,44 @@ }, "attrs": [], "properties": { - "order": 817, + "order": 1966, "id": 248, "name": "store-swap", "prevSize": 32, "code": 59916 }, "setIdx": 0, - "setId": 0, - "iconIdx": 243 + "setId": 2, + "iconIdx": 249 }, { "icon": { "paths": [ - "M292.267 302.080c0-115.627 110.933-174.080 229.973-174.080 69.973 0 128 20.907 166.4 54.613 32.853 27.733 62.293 73.813 62.293 138.24h-128.427c0-13.227-2.133-25.173-6.4-36.267-12.373-36.693-51.2-54.613-96-54.613-79.36 0-99.84 43.52-99.84 72.533 0 20.48 10.667 37.547 31.573 51.627 16.213 10.667 32.853 20.48 60.16 29.867h-196.693c-8.96-14.507-23.040-37.973-23.040-81.92zM896 512v-85.333h-768v85.333h410.453c49.067 19.2 83.627 32 83.627 84.053 0 42.667-34.56 71.253-97.28 71.253-65.707 0-125.013-23.040-125.013-107.093h-126.72c0 23.467 3.413 48.213 10.24 67.413 34.56 97.707 140.373 140.8 241.92 140.8 96.853 0 226.133-37.973 226.133-172.8 0-12.8-0.427-49.493-20.48-82.773h165.12v-0.853z" - ], - "attrs": [], - "tags": [ - "ic-baseline-strikethrough-s" + "M204.8 896c-21.12 0-39.2-7.52-54.24-22.56s-22.56-33.12-22.56-54.24v-384c0-21.12 7.52-39.2 22.56-54.24s33.12-22.56 54.24-22.56h614.4c21.12 0 39.2 7.52 54.24 22.56s22.56 33.12 22.56 54.24v384c0 21.12-7.52 39.2-22.56 54.24s-33.12 22.56-54.24 22.56h-614.4zM204.8 819.2h614.4v-384h-614.4v384zM435.2 780.8l230.4-153.6-230.4-153.6v307.2zM204.8 320v-76.8h614.4v76.8h-614.4zM320 204.8v-76.8h384v76.8h-384z" ], - "defaultCode": 59677, - "grid": 16 - }, - "attrs": [], - "properties": { - "order": 688, - "id": 119, - "name": "strikethrough", - "prevSize": 32, - "code": 59678 - }, - "setIdx": 0, - "setId": 0, - "iconIdx": 244 - }, - { - "icon": { - "paths": [ - "M65.142 967.842c-19.515 0.006-36.594-7.304-51.235-21.934s-21.967-31.705-21.974-51.221l-0.186-536.674c-0.006-19.515 7.304-36.594 21.936-51.236s31.704-21.965 51.22-21.973l829.403-0.286c19.515-0.008 36.598 7.304 51.241 21.935 14.636 14.632 21.962 31.705 21.968 51.22l0.189 536.674c0.006 19.515-7.304 36.591-21.934 51.234s-31.705 21.968-51.221 21.976l-829.407 0.285zM65.115 894.659l829.407-0.285-0.189-536.675-829.404 0.286 0.186 536.674zM390.751 807.944l269.496-181.832-269.622-180.421 0.126 362.252zM75.857 211.615l-0.027-73.183 807.45-0.279 0.028 73.183-807.451 0.279zM235.587 65.196l-0.027-73.183 487.887-0.168 0.028 73.183-487.889 0.168zM65.115 894.659v0z" + "attrs": [ + {} ], - "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "subscription" ], - "grid": 16, - "defaultCode": 59813 + "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 568, - "id": 281, + "order": 1967, + "id": 249, "name": "subscription", "prevSize": 32, - "code": 59813 + "code": 59812 }, "setIdx": 0, - "setId": 0, - "iconIdx": 245 + "setId": 2, + "iconIdx": 250 }, { "icon": { @@ -5998,6 +6742,8 @@ "M490.24 682.667c37.547 0 72.533-11.093 101.973-29.867l104.107 104.107 60.587-60.587-104.107-103.68c18.773-29.867 29.867-64.427 29.867-101.973 0-106.24-85.76-192-192-192s-192 85.76-192 192c0 106.24 85.76 192 191.573 192zM490.667 384c28.288 0 55.42 11.238 75.426 31.242 20.002 20.005 31.241 47.137 31.241 75.425s-11.238 55.42-31.241 75.426c-20.006 20.002-47.138 31.241-75.426 31.241s-55.42-11.238-75.425-31.241c-20.004-20.006-31.242-47.138-31.242-75.426s11.238-55.42 31.242-75.425c20.005-20.004 47.137-31.242 75.425-31.242zM853.333 170.667h-682.667c-46.933 0-85.333 38.4-85.333 85.333v512c0 46.933 38.4 85.333 85.333 85.333h682.667c46.933 0 85.333-38.4 85.333-85.333v-512c0-46.933-38.4-85.333-85.333-85.333zM853.333 768h-682.667v-512h682.667v512z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "summary" ], @@ -6006,15 +6752,15 @@ }, "attrs": [], "properties": { - "order": 818, - "id": 249, + "order": 1968, + "id": 250, "name": "summary", "prevSize": 32, "code": 59710 }, "setIdx": 0, - "setId": 0, - "iconIdx": 246 + "setId": 2, + "iconIdx": 251 }, { "icon": { @@ -6022,6 +6768,8 @@ "M464 632v-215.46c0-26.505-21.495-48-48-48h-72c-53.025 0-96 42.975-96 96.002v119.458c0 53.026 42.975 96 96 96h72c26.505 0 48-21.495 48-48zM392 608h-48c-13.23 0-24-10.769-24-24v-119.458c0-13.231 10.77-24 24-24h48v167.458zM512 128c-214.23 0-377.13 178.245-384 384v24c0 13.261 10.74 24 24 24h24c13.26 0 24-10.739 24-24v-24c0-172.035 139.965-312 312-312 172.036 0 312 139.965 312 312h-0.179c0.119 3.644 0.179 248.58 0.179 248.58 0 35.025-28.395 63.42-63.42 63.42h-152.58c0-39.765-32.235-72-72-72h-48c-39.765 0-72 32.235-72 72s32.235 72 72 72h272.58c74.79 0 135.42-60.629 135.42-135.42v-248.58c-6.869-205.755-169.771-384-384-384zM680 680c53.026 0 96-42.974 96-96v-119.458c0-53.027-42.974-96.002-96-96.002h-72c-26.505 0-48 21.495-48 48v215.46c0 26.505 21.495 48 48 48h72zM632 440.542h48c13.231 0 24 10.769 24 24v119.458c0 13.231-10.769 24-24 24h-48v-167.458z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "support" ], @@ -6030,15 +6778,15 @@ }, "attrs": [], "properties": { - "order": 819, - "id": 250, + "order": 1969, + "id": 251, "name": "support", "prevSize": 32, "code": 59711 }, "setIdx": 0, - "setId": 0, - "iconIdx": 247 + "setId": 2, + "iconIdx": 252 }, { "icon": { @@ -6047,23 +6795,31 @@ "M649.846 886.15c32.689 0 63.409-6.203 92.16-18.609s53.76-29.243 75.028-50.511c21.268-21.268 38.105-46.277 50.511-75.028s18.609-59.471 18.609-92.16c0-32.685-6.203-63.405-18.609-92.156s-29.243-53.76-50.511-75.028c-21.268-21.268-46.277-38.105-75.028-50.511s-59.471-18.609-92.16-18.609c-32.689 0-63.409 6.203-92.16 18.609s-53.76 29.243-75.028 50.511c-21.268 21.268-38.105 46.277-50.511 75.028s-18.609 59.471-18.609 92.156c0 32.689 6.203 63.409 18.609 92.16s29.243 53.76 50.511 75.028c21.268 21.268 46.277 38.105 75.028 50.511s59.471 18.609 92.16 18.609zM827.077 649.846c0 97.883-79.348 177.231-177.231 177.231s-177.231-79.348-177.231-177.231c0-97.883 79.348-177.231 177.231-177.231s177.231 79.348 177.231 177.231z" ], "width": 985, - "attrs": [], + "attrs": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "surveys" ], "grid": 16 }, - "attrs": [], + "attrs": [ + {}, + {} + ], "properties": { - "order": 820, - "id": 251, + "order": 1970, + "id": 252, "name": "surveys", "prevSize": 32, "code": 59807 }, "setIdx": 0, - "setId": 0, - "iconIdx": 248 + "setId": 2, + "iconIdx": 253 }, { "icon": { @@ -6072,6 +6828,8 @@ "M256 512l-170.667 170.667 170.667 170.667v-128h640v-85.333h-640v-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "switch" ], @@ -6080,15 +6838,15 @@ }, "attrs": [], "properties": { - "order": 821, - "id": 252, - "name": "switch-", + "order": 1971, + "id": 253, + "name": "switch-arrows", "prevSize": 32, "code": 59808 }, "setIdx": 0, - "setId": 0, - "iconIdx": 249 + "setId": 2, + "iconIdx": 254 }, { "icon": { @@ -6096,6 +6854,8 @@ "M512 170.667v-128l-170.667 170.667 170.667 170.667v-128c141.227 0 256 114.773 256 256 0 43.093-10.667 84.053-29.867 119.467l62.293 62.293c33.28-52.48 52.907-114.773 52.907-181.76 0-188.587-152.747-341.333-341.333-341.333zM512 768c-141.227 0-256-114.773-256-256 0-43.093 10.667-84.053 29.867-119.467l-62.293-62.293c-33.28 52.48-52.907 114.773-52.907 181.76 0 188.587 152.747 341.333 341.333 341.333v128l170.667-170.667-170.667-170.667v128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "sync" ], @@ -6104,15 +6864,15 @@ }, "attrs": [], "properties": { - "order": 822, - "id": 253, + "order": 1972, + "id": 254, "name": "sync", "prevSize": 32, "code": 59809 }, "setIdx": 0, - "setId": 0, - "iconIdx": 250 + "setId": 2, + "iconIdx": 255 }, { "icon": { @@ -6120,6 +6880,8 @@ "M512 170.667v-128l-170.667 170.667 170.667 170.667v-128c141.227 0 256 114.773 256 256 0 43.093-10.667 84.053-29.867 119.467l62.293 62.293c33.28-52.48 52.907-114.773 52.907-181.76 0-188.587-152.747-341.333-341.333-341.333zM512 768c-141.227 0-256-114.773-256-256 0-43.093 10.667-84.053 29.867-119.467l-62.293-62.293c-33.28 52.48-52.907 114.773-52.907 181.76 0 188.587 152.747 341.333 341.333 341.333v128l170.667-170.667-170.667-170.667v128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "sync" ], @@ -6128,15 +6890,15 @@ }, "attrs": [], "properties": { - "order": 823, - "id": 254, + "order": 1973, + "id": 255, "name": "synchronize", "prevSize": 32, "code": 59712 }, "setIdx": 0, - "setId": 0, - "iconIdx": 251 + "setId": 2, + "iconIdx": 256 }, { "icon": { @@ -6144,6 +6906,8 @@ "M915.234 461.901l-353.135-353.136c-15.002-15.003-35.354-23.432-56.567-23.432h-340.198c-44.183 0-80 35.817-80 80v340.198c0 10.505 2.069 20.907 6.089 30.613s9.914 18.526 17.342 25.954l353.136 353.135c31.241 31.241 81.894 31.245 113.139 0l340.194-340.194c31.241-31.245 31.241-81.899 0-113.139zM518.477 858.658l-353.143-353.126v-340.198h340.198l353.135 353.135-340.19 340.19zM405.333 325.333c0 44.183-35.817 80-80 80s-80-35.817-80-80c0-44.183 35.817-80 80-80s80 35.817 80 80z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "tag" ], @@ -6152,15 +6916,15 @@ }, "attrs": [], "properties": { - "order": 824, - "id": 255, + "order": 1974, + "id": 256, "name": "tag", "prevSize": 32, "code": 59713 }, "setIdx": 0, - "setId": 0, - "iconIdx": 252 + "setId": 2, + "iconIdx": 257 }, { "icon": { @@ -6168,6 +6932,8 @@ "M938.669 298.666h-384.001v85.333h384.001v-85.333zM938.669 639.999h-384.001v85.332h384.001v-85.332zM236.374 469.333l-151.040-151.040 60.16-60.16 90.454 90.453 180.906-180.906 60.16 60.16-240.64 241.493zM236.374 810.669l-151.040-151.040 60.16-60.163 90.454 90.454 180.906-180.907 60.16 60.16-240.64 241.496z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "task" ], @@ -6176,15 +6942,15 @@ }, "attrs": [], "properties": { - "order": 825, - "id": 256, + "order": 1975, + "id": 257, "name": "task", "prevSize": 32, "code": 59714 }, "setIdx": 0, - "setId": 0, - "iconIdx": 253 + "setId": 2, + "iconIdx": 258 }, { "icon": { @@ -6192,23 +6958,29 @@ "M258.133 810.701l-151.467-151.467 59.733-59.733 90.667 90.667 181.333-181.333 59.733 60.8-240 241.067zM258.133 469.367l-151.467-151.468 59.733-59.733 90.667 90.667 181.333-181.333 59.733 60.8-240 241.068zM576 725.367v-85.333h384v85.333h-384zM576 384.033v-85.333h384v85.333h-384z" ], "width": 1067, - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "taskmanager" ], "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 826, - "id": 257, + "order": 1976, + "id": 258, "name": "taskmanager", "prevSize": 32, "code": 59810 }, "setIdx": 0, - "setId": 0, - "iconIdx": 254 + "setId": 2, + "iconIdx": 259 }, { "icon": { @@ -6216,6 +6988,8 @@ "M960 469.333v-341.333h-298.667v128h-256v-128h-298.667v341.333h298.667v-128h85.333v426.667h170.667v128h298.667v-341.333h-298.667v128h-85.333v-341.333h85.333v128h298.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "tiers" ], @@ -6224,15 +6998,15 @@ }, "attrs": [], "properties": { - "order": 827, - "id": 258, + "order": 1977, + "id": 259, "name": "tiers", "prevSize": 32, "code": 59790 }, "setIdx": 0, - "setId": 0, - "iconIdx": 255 + "setId": 2, + "iconIdx": 260 }, { "icon": { @@ -6241,6 +7015,8 @@ "M448 341.333h-42.667v170.667l145.067 85.333 21.333-34.133-128-76.8v-145.067z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "timecard" ], @@ -6249,15 +7025,15 @@ }, "attrs": [], "properties": { - "order": 828, - "id": 259, + "order": 1978, + "id": 260, "name": "timecard", "prevSize": 32, "code": 59801 }, "setIdx": 0, - "setId": 0, - "iconIdx": 256 + "setId": 2, + "iconIdx": 261 }, { "icon": { @@ -6267,6 +7043,8 @@ "M789.333 597.333c-105.984 0-192 86.016-192 192s86.016 192 192 192c105.984 0 192-86.016 192-192s-86.016-192-192-192zM750.933 885.333l-96-96 27.072-27.072 68.928 68.736 145.728-145.728 27.072 27.264-172.8 172.8z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "timecard-approve" ], @@ -6275,15 +7053,15 @@ }, "attrs": [], "properties": { - "order": 829, - "id": 260, + "order": 1979, + "id": 261, "name": "timecard-approve", "prevSize": 32, "code": 59918 }, "setIdx": 0, - "setId": 0, - "iconIdx": 257 + "setId": 2, + "iconIdx": 262 }, { "icon": { @@ -6293,6 +7071,8 @@ "M789.333 981.333c105.984 0 192-86.016 192-192s-86.016-192-192-192c-105.984 0-192 86.016-192 192s86.016 192 192 192zM770.133 693.333h38.4v115.2h-38.4v-115.2zM770.133 846.933h38.4v38.4h-38.4v-38.4z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "timecard-warning" ], @@ -6301,158 +7081,302 @@ }, "attrs": [], "properties": { - "order": 830, - "id": 261, + "order": 1980, + "id": 262, "name": "timecard-warning", "prevSize": 32, "code": 59919 }, "setIdx": 0, - "setId": 0, - "iconIdx": 258 + "setId": 2, + "iconIdx": 263 }, { "icon": { "paths": [ - "M567.296 921.6c-16.384 0-28.16-5.292-35.328-15.872s-8.020-23.724-2.56-39.424l149.504-396.288c4.096-10.924 11.776-20.308 23.040-28.16s23.040-11.776 35.328-11.776c11.604 0 23.212 3.924 34.816 11.776s19.456 17.236 23.552 28.16l149.504 396.288c5.46 15.7 4.608 28.844-2.56 39.424s-19.284 15.872-36.352 15.872c-7.508 0-14.336-2.388-20.48-7.168s-10.58-10.58-13.312-17.408l-34.816-100.352h-198.656l-35.84 100.352c-2.732 6.828-7.508 12.628-14.336 17.408s-13.996 7.168-21.504 7.168zM663.552 724.992h147.456l-71.68-202.752h-4.096l-71.68 202.752zM313.344 370.688c10.923 19.797 22.528 38.059 34.816 54.784 12.288 16.724 26.624 33.964 43.008 51.712 30.036-32.768 54.956-66.388 74.752-100.864 19.796-34.475 36.524-71.168 50.176-110.080h-413.696c-11.605 0-21.333-3.925-29.184-11.776s-11.776-17.579-11.776-29.184c0-11.605 3.925-21.333 11.776-29.184s17.579-11.776 29.184-11.776h245.76v-40.96c0-11.605 3.925-21.333 11.776-29.184s17.579-11.776 29.184-11.776c11.605 0 21.332 3.925 29.184 11.776s11.776 17.579 11.776 29.184v40.96h245.76c11.604 0 21.332 3.925 29.184 11.776s11.776 17.579 11.776 29.184c0 11.605-3.924 21.333-11.776 29.184s-17.58 11.776-29.184 11.776h-77.824c-14.336 48.469-33.792 95.573-58.368 141.312-24.576 45.74-54.956 88.748-91.136 129.024l98.304 100.352-30.72 83.968-126.976-126.976-176.128 176.128c-7.509 7.508-17.067 11.264-28.672 11.264s-21.163-3.756-28.672-11.264c-7.509-7.508-11.264-17.068-11.264-28.672s3.755-21.164 11.264-28.672l178.176-178.176c-18.432-21.164-35.499-42.496-51.2-64s-29.696-44.204-41.984-68.096c-7.509-14.336-7.851-26.965-1.024-37.888s18.773-16.384 35.84-16.384c6.827 0 13.995 2.219 21.504 6.656s12.971 9.728 16.384 15.872z" + "M298.667 768q-106.667 0-181.333-74.667t-74.667-181.333 74.667-181.333 181.333-74.667h426.667q106.667 0 181.333 74.667t74.667 181.333-74.667 181.333-181.333 74.667h-426.667zM298.667 682.667h426.667q70.4 0 120.533-50.133t50.133-120.533-50.133-120.533-120.533-50.133h-426.667q-70.4 0-120.533 50.133t-50.133 120.533 50.133 120.533 120.533 50.133zM298.667 640q53.333 0 90.667-37.333t37.333-90.667-37.333-90.667-90.667-37.333-90.667 37.333-37.333 90.667 37.333 90.667 90.667 37.333z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ - "translation" + "toggle off" ], + "defaultCode": 60447, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 833, - "id": 264, - "name": "translation", + "order": 1981, + "id": 263, + "name": "toggle-off", "prevSize": 32, - "code": 59811 - }, - "setIdx": 0, - "setId": 0, - "iconIdx": 259 + "codes": [ + 60447, + 60559, + 60560, + 60561, + 60562, + 60563, + 60564, + 60565, + 60566, + 60567, + 60568, + 60569, + 60570, + 60571, + 60572, + 60573, + 60574, + 60575, + 60576, + 60577, + 60578, + 60579, + 60580, + 60581, + 60582, + 60583, + 60584, + 60585, + 60586, + 60587, + 60588, + 60589, + 60590, + 60591, + 60592, + 60593, + 60594, + 60595, + 60596, + 60597, + 60598, + 60599, + 60600, + 60601, + 60602, + 60603, + 60604, + 60605, + 60606, + 60607, + 60608, + 60609, + 60610, + 60611, + 60612, + 60613, + 60614, + 60615, + 60616, + 60617, + 60618, + 60619, + 60620, + 60621, + 60622, + 60623, + 60624, + 60625, + 60626, + 60627, + 60628, + 60629, + 60630, + 60631, + 60632, + 60633, + 60634, + 60635, + 60636, + 60637, + 60638, + 60639, + 60640, + 60641, + 60642, + 60643, + 60644, + 60645, + 60646, + 60647, + 60648, + 60649, + 60650, + 60651, + 60652, + 60653, + 60654, + 60655, + 60656, + 60657, + 60658, + 60659, + 60660, + 60661, + 60662, + 60663, + 60664, + 60665, + 60666, + 60667, + 60668 + ], + "code": 60447 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 264 }, { "icon": { "paths": [ - "M256 810.667c0 46.933 38.4 85.333 85.333 85.333h341.333c46.933 0 85.333-38.4 85.333-85.333v-512h-512v512zM810.667 170.667h-149.333l-42.667-42.667h-213.333l-42.667 42.667h-149.333v85.333h597.333v-85.333z" + "M298.667 768q-106.667 0-181.333-74.667t-74.667-181.333 74.667-181.333 181.333-74.667h426.667q106.667 0 181.333 74.667t74.667 181.333-74.667 181.333-181.333 74.667h-426.667zM298.667 682.667h426.667q70.4 0 120.533-50.133t50.133-120.533-50.133-120.533-120.533-50.133h-426.667q-70.4 0-120.533 50.133t-50.133 120.533 50.133 120.533 120.533 50.133zM725.333 640q53.333 0 90.667-37.333t37.333-90.667-37.333-90.667-90.667-37.333-90.667 37.333-37.333 90.667 37.333 90.667 90.667 37.333z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ - "trash" + "toggle on" ], - "defaultCode": 59816, + "defaultCode": 59814, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 834, - "id": 265, - "name": "trash", + "order": 1982, + "id": 264, + "name": "toggle-on", "prevSize": 32, - "code": 59816 + "codes": [ + 59814, + 59815 + ], + "code": 59814 }, "setIdx": 0, - "setId": 0, - "iconIdx": 260 + "setId": 2, + "iconIdx": 265 }, { "icon": { "paths": [ - "M512.010 85.336c-234.666 0-426.666 192-426.666 426.667s192 426.666 426.666 426.666c234.665 0 426.665-192 426.665-426.666s-192-426.667-426.665-426.667zM170.677 512.003c0-187.733 153.6-341.333 341.333-341.333 76.8 0 149.334 25.6 209.065 72.533l-477.865 477.866c-46.933-59.731-72.533-132.266-72.533-209.066zM512.010 853.338c-76.8 0-149.333-25.6-209.066-72.538l477.869-477.864c46.931 59.734 72.531 132.267 72.531 209.067 0 187.735-153.6 341.335-341.334 341.335z" + "M567.296 921.6c-16.384 0-28.16-5.292-35.328-15.872s-8.020-23.724-2.56-39.424l149.504-396.288c4.096-10.924 11.776-20.308 23.040-28.16s23.040-11.776 35.328-11.776c11.604 0 23.212 3.924 34.816 11.776s19.456 17.236 23.552 28.16l149.504 396.288c5.46 15.7 4.608 28.844-2.56 39.424s-19.284 15.872-36.352 15.872c-7.508 0-14.336-2.388-20.48-7.168s-10.58-10.58-13.312-17.408l-34.816-100.352h-198.656l-35.84 100.352c-2.732 6.828-7.508 12.628-14.336 17.408s-13.996 7.168-21.504 7.168zM663.552 724.992h147.456l-71.68-202.752h-4.096l-71.68 202.752zM313.344 370.688c10.923 19.797 22.528 38.059 34.816 54.784 12.288 16.724 26.624 33.964 43.008 51.712 30.036-32.768 54.956-66.388 74.752-100.864 19.796-34.475 36.524-71.168 50.176-110.080h-413.696c-11.605 0-21.333-3.925-29.184-11.776s-11.776-17.579-11.776-29.184c0-11.605 3.925-21.333 11.776-29.184s17.579-11.776 29.184-11.776h245.76v-40.96c0-11.605 3.925-21.333 11.776-29.184s17.579-11.776 29.184-11.776c11.605 0 21.332 3.925 29.184 11.776s11.776 17.579 11.776 29.184v40.96h245.76c11.604 0 21.332 3.925 29.184 11.776s11.776 17.579 11.776 29.184c0 11.605-3.924 21.333-11.776 29.184s-17.58 11.776-29.184 11.776h-77.824c-14.336 48.469-33.792 95.573-58.368 141.312-24.576 45.74-54.956 88.748-91.136 129.024l98.304 100.352-30.72 83.968-126.976-126.976-176.128 176.128c-7.509 7.508-17.067 11.264-28.672 11.264s-21.163-3.756-28.672-11.264c-7.509-7.508-11.264-17.068-11.264-28.672s3.755-21.164 11.264-28.672l178.176-178.176c-18.432-21.164-35.499-42.496-51.2-64s-29.696-44.204-41.984-68.096c-7.509-14.336-7.851-26.965-1.024-37.888s18.773-16.384 35.84-16.384c6.827 0 13.995 2.219 21.504 6.656s12.971 9.728 16.384 15.872z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ - "unclaim" + "translation" ], - "defaultCode": 59713, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 835, - "id": 266, - "name": "unclaim", + "order": 1983, + "id": 265, + "name": "translation", "prevSize": 32, - "code": 59715 + "code": 59811 }, "setIdx": 0, - "setId": 0, - "iconIdx": 261 + "setId": 2, + "iconIdx": 266 }, { "icon": { "paths": [ - "M512 725.333c141.227 0 256-114.773 256-256v-341.333h-106.667v341.333c0 82.347-66.987 149.333-149.333 149.333s-149.333-66.987-149.333-149.333v-341.333h-106.667v341.333c0 141.227 114.773 256 256 256zM213.333 810.667v85.333h597.333v-85.333h-597.333z" + "M256 810.667c0 46.933 38.4 85.333 85.333 85.333h341.333c46.933 0 85.333-38.4 85.333-85.333v-512h-512v512zM810.667 170.667h-149.333l-42.667-42.667h-213.333l-42.667 42.667h-149.333v85.333h597.333v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ - "ic-baseline-format-underlined" + "trash" ], - "defaultCode": 59676, + "defaultCode": 59816, "grid": 16 }, "attrs": [], "properties": { - "order": 687, - "id": 118, - "name": "underlined", + "order": 1984, + "id": 266, + "name": "trash", "prevSize": 32, - "code": 59677 + "code": 59816 }, "setIdx": 0, - "setId": 0, - "iconIdx": 262 + "setId": 2, + "iconIdx": 267 }, { "icon": { "paths": [ - "M576 298.667c73.553 0 144.094 29.219 196.105 81.229s81.229 122.551 81.229 196.104c0 73.553-29.218 144.094-81.229 196.105s-122.551 81.229-196.105 81.229h-149.333v-85.333h149.333c106.667 0 192-85.333 192-192s-85.333-192-192-192h-241.92l131.413 131.84-60.16 60.16-234.667-234.667 234.667-234.667 60.587 60.16-131.84 131.84h241.92zM256 768h85.333v85.333h-85.333v-85.333z" + "M512.010 85.336c-234.666 0-426.666 192-426.666 426.667s192 426.666 426.666 426.666c234.665 0 426.665-192 426.665-426.666s-192-426.667-426.665-426.667zM170.677 512.003c0-187.733 153.6-341.333 341.333-341.333 76.8 0 149.334 25.6 209.065 72.533l-477.865 477.866c-46.933-59.731-72.533-132.266-72.533-209.066zM512.010 853.338c-76.8 0-149.333-25.6-209.066-72.538l477.869-477.864c46.931 59.734 72.531 132.267 72.531 209.067 0 187.735-153.6 341.335-341.334 341.335z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ - "mdi-undo-variant" + "unclaim" ], - "defaultCode": 59686, + "defaultCode": 59713, "grid": 16 }, "attrs": [], "properties": { - "order": 720, - "id": 151, - "name": "undo-variant", + "order": 1985, + "id": 267, + "name": "unclaim", "prevSize": 32, - "code": 59686 + "code": 59715 }, "setIdx": 0, - "setId": 0, - "iconIdx": 263 + "setId": 2, + "iconIdx": 268 }, { "icon": { "paths": [ - "M511.967 530.115l-362.666-231.464v490.664h411.734c0 9.958 0.886 20.803 2.668 32.538 1.777 11.73 4.086 22.221 6.932 31.462h-421.334c-17.067 0-32-6.574-44.8-19.732-12.8-13.153-19.2-27.909-19.2-44.268v-554.664c0-16.356 6.4-31.111 19.2-44.267s27.733-19.733 44.8-19.733h725.334c16.353 0 31.109 6.578 44.268 19.733 13.153 13.156 19.732 27.911 19.732 44.267v310.399c-7.823-4.265-17.956-8.356-30.403-12.268-12.442-3.912-23.644-6.932-33.597-9.068v-225.064l-362.668 231.464zM511.967 461.85l362.668-227.2h-725.334l362.666 227.2zM824.499 981.315c-55.183 0-102.226-19.2-141.123-57.6s-58.342-85.335-58.342-140.815c0-55.475 19.446-102.764 58.342-141.865s85.939-58.65 141.123-58.65c55.188 0 102.226 19.548 141.123 58.65s58.342 86.39 58.342 141.865c0 55.48-19.446 102.415-58.342 140.815s-85.934 57.6-141.123 57.6zM703.964 799.985h241.070v-42.67h-241.070v42.67z" + "M477.092 494.182l-279.274-174.544v349.090h279.274c0 12.218 0.872 24 2.618 35.346 1.744 11.346 4.362 22.836 7.854 34.472h-289.746c-19.2 0-35.637-6.836-49.309-20.51-13.673-13.672-20.509-30.108-20.509-49.308v-418.91c0-19.2 6.836-35.636 20.509-49.308 13.673-13.674 30.109-20.51 49.309-20.51h558.546c19.2 0 35.636 6.836 49.31 20.51 13.672 13.672 20.508 30.108 20.508 49.308v198.982c-10.472-5.236-21.672-9.6-33.6-13.090-11.926-3.492-24-6.11-36.218-7.854v-108.22l-279.272 174.546zM477.092 424.364l279.272-174.546h-558.547l279.275 174.546zM721.454 843.272c-48.29 0-89.454-17.018-123.49-51.054s-51.054-75.2-51.054-123.49c0-48.292 17.018-89.454 51.054-123.49 34.036-34.038 75.2-51.056 123.49-51.056 48.292 0 89.456 17.018 123.492 51.056 34.036 34.036 51.054 75.198 51.054 123.49 0 48.29-17.018 89.454-51.054 123.49s-75.2 51.054-123.492 51.054zM616.728 686.182h209.454v-34.91h-209.454v34.91z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "unsubscribe" ], - "grid": 16, - "defaultCode": 59815 + "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 566, - "id": 279, + "order": 1986, + "id": 268, "name": "unsubscribe", "prevSize": 32, - "code": 59815 + "code": 59813 }, "setIdx": 0, - "setId": 0, - "iconIdx": 264 + "setId": 2, + "iconIdx": 269 }, { "icon": { @@ -6460,6 +7384,8 @@ "M896 431.787h-289.28l116.907-120.32c-116.48-115.2-305.067-119.467-421.547-4.267-116.48 115.627-116.48 302.080 0 417.707s305.067 115.627 421.547 0c58.027-57.173 87.040-124.16 87.040-208.64h85.333c0 84.48-37.547 194.133-112.64 268.373-149.76 148.48-392.96 148.48-542.72 0-149.333-148.053-150.613-388.693-0.853-536.747s389.973-148.053 539.733 0l116.48-119.893v303.787zM533.333 341.333v181.333l149.333 88.747-30.72 51.627-182.613-108.373v-213.333h64z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "update" ], @@ -6468,15 +7394,15 @@ }, "attrs": [], "properties": { - "order": 836, - "id": 267, + "order": 1987, + "id": 269, "name": "update", "prevSize": 32, "code": 59818 }, "setIdx": 0, - "setId": 0, - "iconIdx": 265 + "setId": 2, + "iconIdx": 270 }, { "icon": { @@ -6484,6 +7410,8 @@ "M384 682.667h256v-256h170.667l-298.667-298.667-298.667 298.667h170.667v256zM213.333 768h597.333v85.333h-597.333v-85.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "upload" ], @@ -6492,15 +7420,15 @@ }, "attrs": [], "properties": { - "order": 837, - "id": 268, + "order": 1988, + "id": 270, "name": "upload", "prevSize": 32, "code": 59921 }, "setIdx": 0, - "setId": 0, - "iconIdx": 266 + "setId": 2, + "iconIdx": 271 }, { "icon": { @@ -6508,6 +7436,8 @@ "M512 512c94.293 0 170.667-76.373 170.667-170.667s-76.373-170.667-170.667-170.667c-94.293 0-170.667 76.373-170.667 170.667s76.373 170.667 170.667 170.667zM512 597.333c-113.92 0-341.333 57.173-341.333 170.667v85.333h682.667v-85.333c0-113.493-227.413-170.667-341.333-170.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "user" ], @@ -6516,15 +7446,15 @@ }, "attrs": [], "properties": { - "order": 838, - "id": 269, + "order": 1989, + "id": 271, "name": "user", "prevSize": 32, "code": 59925 }, "setIdx": 0, - "setId": 0, - "iconIdx": 267 + "setId": 2, + "iconIdx": 272 }, { "icon": { @@ -6536,6 +7466,8 @@ "M705.28 590.080c37.973 35.413 62.72 79.787 62.72 135.253v128h85.333v-128c0-61.867-67.84-107.093-148.053-135.253z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "user-add" ], @@ -6544,15 +7476,15 @@ }, "attrs": [], "properties": { - "order": 839, - "id": 270, + "order": 1990, + "id": 272, "name": "user-add", "prevSize": 32, "code": 59922 }, "setIdx": 0, - "setId": 0, - "iconIdx": 268 + "setId": 2, + "iconIdx": 273 }, { "icon": { @@ -6560,6 +7492,8 @@ "M512 544c69.547 0 130.987 16.64 180.907 38.4 46.080 20.48 75.093 66.56 75.093 116.48v69.12h-512v-68.693c0-50.347 29.013-96.427 75.093-116.48 49.92-22.187 111.36-38.827 180.907-38.827zM170.667 554.667c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM218.88 601.6c-15.787-2.56-31.573-4.267-48.213-4.267-42.24 0-82.347 8.96-118.613 24.747-31.573 13.653-52.053 44.373-52.053 78.933v66.987h192v-68.693c0-35.413 9.813-68.693 26.88-97.707zM853.333 554.667c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM1024 701.013c0-34.56-20.48-65.28-52.053-78.933-36.267-15.787-76.373-24.747-118.613-24.747-16.64 0-32.427 1.707-48.213 4.267 17.067 29.013 26.88 62.293 26.88 97.707v68.693h192v-66.987zM512 256c70.827 0 128 57.173 128 128s-57.173 128-128 128c-70.827 0-128-57.173-128-128s57.173-128 128-128z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "user-group" ], @@ -6568,15 +7502,15 @@ }, "attrs": [], "properties": { - "order": 840, - "id": 271, + "order": 1991, + "id": 273, "name": "user-group", "prevSize": 32, "code": 59923 }, "setIdx": 0, - "setId": 0, - "iconIdx": 269 + "setId": 2, + "iconIdx": 274 }, { "icon": { @@ -6584,6 +7518,8 @@ "M682.667 469.333c70.827 0 127.573-57.173 127.573-128s-56.747-128-127.573-128c-70.827 0-128 57.173-128 128s57.173 128 128 128zM341.333 469.333c70.827 0 127.573-57.173 127.573-128s-56.747-128-127.573-128c-70.827 0-128 57.173-128 128s57.173 128 128 128zM341.333 554.667c-99.413 0-298.667 49.92-298.667 149.333v106.667h597.333v-106.667c0-99.413-199.253-149.333-298.667-149.333zM682.667 554.667c-12.373 0-26.453 0.853-41.387 2.133 49.493 35.84 84.053 84.053 84.053 147.2v106.667h256v-106.667c0-99.413-199.253-149.333-298.667-149.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "user-multiple" ], @@ -6592,15 +7528,15 @@ }, "attrs": [], "properties": { - "order": 841, - "id": 272, + "order": 1992, + "id": 274, "name": "user-multiple", "prevSize": 32, "code": 59924 }, "setIdx": 0, - "setId": 0, - "iconIdx": 270 + "setId": 2, + "iconIdx": 275 }, { "icon": { @@ -6608,6 +7544,8 @@ "M903.872 375.011c-1.097 2.004-2.692 3.687-4.638 4.884s-4.169 1.867-6.455 1.942l-90.88 1.707c-1.673 0.005-3.332-0.333-4.877-0.993-1.54-0.66-2.927-1.629-4.083-2.847l-35.413-33.707-9.387 40.96c-0.589 2.372-1.818 4.538-3.546 6.266s-3.895 2.955-6.268 3.547l-84.907 15.445c78.080 12.8 223.573 61.866 224 253.44 0 2.406-0.683 4.766-1.967 6.805-1.284 2.035-3.115 3.674-5.286 4.715-2.172 1.054-4.595 1.493-7.002 1.267-2.411-0.226-4.71-1.105-6.652-2.547l-135.253-104.96c-1.89-1.779-3.349-3.968-4.267-6.4l-23.040-69.547-31.147 45.653c-1.011 1.506-2.334 2.782-3.883 3.738-1.545 0.956-3.273 1.574-5.077 1.809-1.847 0.158-3.708-0.060-5.47-0.649-1.762-0.585-3.383-1.527-4.77-2.765l-79.787-71.253-5.252 1.323c10.53 11.767 38.767 59.341 38.767 231.155 0 46.263-1.024 83.52-2.624 113.493 100.8 17.199 173.291 64.951 173.291 121.173h-512c0-64.482 95.363-117.828 219.418-126.703 8.802-33.489 15.249-70.724 15.249-107.964v-214.050l-4.757 1.199-110.505 77.653c-2.347 1.647-5.178 2.458-8.041 2.304-2.863-0.158-5.59-1.267-7.746-3.157l-28.16-25.173-5.12 80.213c-0.126 1.843-0.649 3.635-1.533 5.252-0.884 1.621-2.107 3.034-3.587 4.134l-90.88 68.693c-1.832 1.31-3.956 2.146-6.188 2.445s-4.501 0.047-6.612-0.738c-2.035-0.926-3.805-2.351-5.147-4.139-1.342-1.792-2.213-3.887-2.533-6.101-11.52-91.307 25.173-263.253 229.545-272.64l-97.278-40.107c-2.738-1.060-5.012-3.056-6.419-5.634s-1.853-5.57-1.261-8.446l11.093-58.453-65.707 42.24c-1.332 0.985-2.854 1.683-4.47 2.050s-3.29 0.396-4.916 0.083l-132.267-26.88c-2.464-0.386-4.742-1.544-6.506-3.308s-2.921-4.042-3.307-6.506c-0.591-2.422-0.462-4.964 0.372-7.314s2.336-4.405 4.321-5.913c180.907-133.12 302.078-38.827 375.891 65.707-28.587-102.4-13.227-218.88 129.28-239.36 2.159-0.197 4.331 0.127 6.332 0.944 2.005 0.817 3.785 2.103 5.188 3.75 1.472 1.574 2.453 3.539 2.833 5.658 0.375 2.12 0.137 4.303-0.7 6.288-5.547 17.493-14.933 44.8-26.027 75.52l-44.8 7.68 35.413 19.627c-14.874 43.799-33.574 86.202-55.893 126.72 91.733-114.773 254.293-141.227 342.613-12.373 1.34 1.905 2.116 4.148 2.236 6.473s-0.418 4.636-1.553 6.669z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "vacation" ], @@ -6616,15 +7554,15 @@ }, "attrs": [], "properties": { - "order": 842, - "id": 273, + "order": 1993, + "id": 275, "name": "vacation", "prevSize": 32, "code": 59926 }, "setIdx": 0, - "setId": 0, - "iconIdx": 271 + "setId": 2, + "iconIdx": 276 }, { "icon": { @@ -6632,6 +7570,8 @@ "M512 42.667l-384 170.667v256c0 236.8 163.84 458.24 384 512 220.16-53.76 384-275.2 384-512v-256l-384-170.667zM426.667 725.333l-170.667-170.667 60.16-60.16 110.507 110.080 281.173-281.173 60.16 60.587-341.333 341.333z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "verified" ], @@ -6640,15 +7580,15 @@ }, "attrs": [], "properties": { - "order": 843, - "id": 274, + "order": 1994, + "id": 276, "name": "verified", "prevSize": 32, "code": 59927 }, "setIdx": 0, - "setId": 0, - "iconIdx": 272 + "setId": 2, + "iconIdx": 277 }, { "icon": { @@ -6656,6 +7596,8 @@ "M640 341.333v341.333h-426.667v-341.333h426.667zM682.667 256h-512c-23.467 0-42.667 19.2-42.667 42.667v426.667c0 23.467 19.2 42.667 42.667 42.667h512c23.467 0 42.667-19.2 42.667-42.667v-149.333l170.667 170.667v-469.333l-170.667 170.667v-149.333c0-23.467-19.2-42.667-42.667-42.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "video" ], @@ -6664,15 +7606,15 @@ }, "attrs": [], "properties": { - "order": 844, - "id": 275, + "order": 1995, + "id": 277, "name": "video", "prevSize": 32, "code": 59764 }, "setIdx": 0, - "setId": 0, - "iconIdx": 273 + "setId": 2, + "iconIdx": 278 }, { "icon": { @@ -6680,48 +7622,60 @@ "M597.333 234.667c46.933 0 85.333-38.4 85.333-85.333s-38.4-85.333-85.333-85.333c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333zM439.467 379.733l-119.467 601.6h89.6l76.8-341.333 89.6 85.333v256h85.333v-320l-89.6-85.333 25.6-128c55.467 64 140.8 106.667 234.667 106.667v-85.333c-81.067 0-149.333-42.667-183.467-102.4l-42.667-68.267c-23.893-37.973-71.68-53.333-113.067-35.84l-215.467 91.307v200.533h85.333v-145.067l76.8-29.867z" ], "width": 1067, - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "walk" ], "defaultCode": 59715, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 845, - "id": 276, + "order": 1996, + "id": 278, "name": "walk", "prevSize": 32, "code": 59782 }, "setIdx": 0, - "setId": 0, - "iconIdx": 274 + "setId": 2, + "iconIdx": 279 }, { "icon": { "paths": [ - "M42.667 384l85.333 85.334c212.053-212.054 555.947-212.054 768 0l85.333-85.334c-258.987-258.987-679.253-258.987-938.667 0zM384 725.333l128 128 128-128c-70.4-70.827-185.173-70.827-256 0zM213.333 554.667l85.333 85.333c117.76-117.76 308.907-117.76 426.667 0l85.333-85.333c-164.693-164.694-432.213-164.694-597.333 0z" + "M331.2 603.2l-67.2-68.8c31.466-31.466 68.4-56.4 110.8-74.8s88.134-27.6 137.2-27.6c49.066 0 94.8 9.334 137.2 28s79.334 44 110.8 76l-67.2 67.2c-23.466-23.466-50.666-41.866-81.6-55.2s-64-20-99.2-20c-35.2 0-68.266 6.666-99.2 20s-58.134 31.734-81.6 55.2zM195.2 467.2l-67.2-67.2c49.067-50.134 106.4-89.334 172-117.6s136.266-42.4 212-42.4c75.734 0 146.4 14.134 212 42.4s122.934 67.466 172 117.6l-67.2 67.2c-41.066-41.066-88.666-73.2-142.8-96.4s-112.134-34.8-174-34.8c-61.866 0-119.866 11.6-174 34.8s-101.734 55.334-142.8 96.4zM512 784l112.8-113.6c-14.4-14.4-31.2-25.734-50.4-34s-40-12.4-62.4-12.4c-22.4 0-43.2 4.134-62.4 12.4s-36 19.6-50.4 34l112.8 113.6z" ], - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "wifi" ], "defaultCode": 59928, "grid": 16 }, - "attrs": [], + "attrs": [ + {} + ], "properties": { - "order": 846, - "id": 277, + "order": 1997, + "id": 279, "name": "wifi", "prevSize": 32, "code": 59928 }, "setIdx": 0, - "setId": 0, - "iconIdx": 275 + "setId": 2, + "iconIdx": 280 }, { "icon": { @@ -6729,6 +7683,8 @@ "M213.333 128c-47.36 0-85.333 37.973-85.333 85.333v597.333c0 22.63 8.99 44.335 24.994 60.339s37.708 24.994 60.34 24.994h597.333c22.63 0 44.335-8.99 60.339-24.994s24.994-37.709 24.994-60.339v-298.667h-85.333v298.667h-597.333v-597.333h298.667v-85.333h-298.667zM758.613 170.667c-7.68 0.065-15.027 3.127-20.48 8.533l-52.053 51.627 106.667 106.667 52.053-51.627c11.093-11.093 11.093-29.867 0-40.533l-66.133-66.133c-5.547-5.547-12.8-8.533-20.053-8.533zM655.787 261.12l-314.453 314.88v106.667h106.667l314.453-314.88-106.667-106.667z" ], "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, "tags": [ "write" ], @@ -6737,15 +7693,15 @@ }, "attrs": [], "properties": { - "order": 847, - "id": 278, + "order": 1998, + "id": 280, "name": "write", "prevSize": 32, "code": 59820 }, "setIdx": 0, - "setId": 0, - "iconIdx": 276 + "setId": 2, + "iconIdx": 281 } ], "height": 1024, @@ -6777,8 +7733,8 @@ "autoHost": true, "includeMetadata": true, "showMetrics": false, - "showMetadata": false, - "showVersion": false, + "showMetadata": true, + "showVersion": true, "showSelector": false }, "imagePref": { diff --git a/lib/assets/fonts/zds.ttf b/lib/assets/fonts/zds.ttf index 30cdc480261dee3e36224bce289be45db421dfb8..d8aa19ede96553814e3791fcc4999805de4a6ab8 100644 GIT binary patch delta 5745 zcmcIo3sjV48vg$InSWr0`(@=f#UtytZ#X}JjyJC(th!=}2mkJOCB9a+KHyKgY2 zN?%>Gsa_}(x*0q74UmG@)U5WaE$FvA&DeXs;H0#E?S=*>qJj78yWV)x?NvbGESNbk zi3u!N&J!Z#W+BGsw*FiFfAzQYH@&}hzwK^tn-5BY{I)Pr{zA}Y-L)_#T9}Hlgd_ot z!PgIxsgWm|MTL`O zCk)m&K1WI=fK^V-3f|%rB{2D@(>a@cxo6j1CkPh2A-7#Oi)JiJ>Kv>ghp&k8LFWk^9~R{c&fyB@j`MiMUbsspVX$Xj<6=z_^B8qa zQ%FX)a>5^BFmA^PHvrCZPm?g1&7%CYdn~~{qWqS73o+gTlj$BFDjI-&xzvlRehJvs z`x419r>owt6GpcKK2?fbtA9(u=k*^e`1rWT38T$;-&2ZQfQ=iNxHv))K&!wydf}!vuo^2 zD;YQ`8MUpr3-GAnpeR zaeK%p>Kfv?gZ+S|gs(`BS>8%`jc^d)!9*S?+SDd>lN|9t63>1e;E^OAH0mx(-evFl zO-^u5K^b{K8`Tatl2xg<$qcGWXKEn988HHcmH7otR>0(~OkO8{z!h0hB>wLgv1&@Ndk$Oc>X4IB$||FRAmB z>AdQOJ`Z3)a%E14T$evZq3+M0L^u-EF6QSeIJ|&|g65hEn#mj-GuI0Wh=LL37V?ZS zs@6h#2Y~V>V4N3nR@)Q=a0n)wEB+ z;l&(-ck}sT7rvGl%BS;r-%wa3yq_?ODTUPS3 z@EE9ES-FQ769a60lrJA*ecfeB?h-U-T@P8p?YMI_uUaJFQP-3c<&`aURja#AqQjMAEnl8jo}#AzhfJ=0Eo%XvWf|a8Ql&m>v&G{4Ca8w?5lf{$8Kd+3A%E?$yGau6MKj&~{~FeOgbdB79^tt1RM>R<{8UM_bk zTfKvvbvj9s+;x&5X*^w2DoLkSJBlt|8cA|=bo6z1_k|xx(s;Ruj%u||x_!sRQv+n3 zJ7`HdopX>k-T_)KblNp<(qiEn+OFPn0avf(+XLmQ`sav)ZPHWEw=&{u^}kZ&``6j+ zELq>Iw0{swVOeruL#V9Vuv_soxS@vdL9n84*zRVHhWWzH9G*BaO`-CIhAiaJiS6Im zMHV3%;!Ffako@OHekNgz#wKnN@y@2V6;Bl#A193Qj%++g7uqe%C^GQD1 z#`iFW(!2Q!^hws*pJ*18f%eHb`yl(NM!JDP8kwpALrdk!Tg^7UJi7H51&>Dip83os zH@9!&HzefYlfH_%RD|^R2Fx+$Pwu-$_Bva^Lfu zg$_P_o*zSqle;-at2?`2C##Ww3wjy}4*@>g!xs-%yX6Ib8sbgQtrxnL=z3nPRdiLm zc$edYP0udtP3<;N=!Y+xIbXFbMr# z?qD_GLwk9k$Pe#dM;zq$_4hl|-h^zJjz!2FWpJaguULul^gdosP&9k)_uzFyP2x2Xo@m8#5(^*5y(haPIEtSj8g+^O3+n@kb b?efODn)S@YYT0tu$m&=PTW?btKDYjVKhaBf delta 5409 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 diff --git a/lib/assets/images/chat.svg b/lib/assets/images/chat.svg index dec1552..3050f91 100644 --- a/lib/assets/images/chat.svg +++ b/lib/assets/images/chat.svg @@ -1,34 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/lib/assets/images/clock.svg b/lib/assets/images/clock.svg new file mode 100644 index 0000000..9a6534b --- /dev/null +++ b/lib/assets/images/clock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/assets/images/connection_loss.svg b/lib/assets/images/connection_loss.svg new file mode 100644 index 0000000..9277455 --- /dev/null +++ b/lib/assets/images/connection_loss.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/assets/images/dark_mode.svg b/lib/assets/images/dark_mode.svg new file mode 100644 index 0000000..ad62217 --- /dev/null +++ b/lib/assets/images/dark_mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/assets/images/internet_fail.svg b/lib/assets/images/internet_fail.svg new file mode 100644 index 0000000..329aad0 --- /dev/null +++ b/lib/assets/images/internet_fail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/assets/images/light_mode.svg b/lib/assets/images/light_mode.svg new file mode 100644 index 0000000..0729bd0 --- /dev/null +++ b/lib/assets/images/light_mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/assets/images/map.svg b/lib/assets/images/map.svg index f962e0e..5f4db49 100644 --- a/lib/assets/images/map.svg +++ b/lib/assets/images/map.svg @@ -1,8 +1 @@ - - - - - - - - + \ No newline at end of file diff --git a/lib/assets/images/punch.svg b/lib/assets/images/punch.svg deleted file mode 100644 index 2ee2538..0000000 --- a/lib/assets/images/punch.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/lib/assets/images/sleeping_zebra.svg b/lib/assets/images/sleeping_zebra.svg index 4aba1ed..686522d 100644 --- a/lib/assets/images/sleeping_zebra.svg +++ b/lib/assets/images/sleeping_zebra.svg @@ -1,65 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/lib/assets/images/system_mode.svg b/lib/assets/images/system_mode.svg new file mode 100644 index 0000000..a8ce578 --- /dev/null +++ b/lib/assets/images/system_mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/assets/js/quill.min.js b/lib/assets/js/quill.min.js new file mode 100644 index 0000000..ff30fd9 --- /dev/null +++ b/lib/assets/js/quill.min.js @@ -0,0 +1,8 @@ +/*! + * Quill Editor v1.3.6 + * https://quilljs.com/ + * Copyright (c) 2014, Jason Chen + * Copyright (c) 2013, salesforce.com + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Quill=e():t.Quill=e()}("undefined"!=typeof self?self:this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};return e.m=t,e.c=n,e.d=function(t,n,r){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:r})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=45)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(17),o=n(18),i=n(19),l=n(48),a=n(49),s=n(50),u=n(51),c=n(52),f=n(11),h=n(29),p=n(30),d=n(28),y=n(1),v={Scope:y.Scope,create:y.create,find:y.find,query:y.query,register:y.register,Container:r.default,Format:o.default,Leaf:i.default,Embed:u.default,Scroll:l.default,Block:s.default,Inline:a.default,Text:c.default,Attributor:{Attribute:f.default,Class:h.default,Style:p.default,Store:d.default}};e.default=v},function(t,e,n){"use strict";function r(t,e){var n=i(t);if(null==n)throw new s("Unable to create "+t+" blot");var r=n;return new r(t instanceof Node||t.nodeType===Node.TEXT_NODE?t:r.create(e),e)}function o(t,n){return void 0===n&&(n=!1),null==t?null:null!=t[e.DATA_KEY]?t[e.DATA_KEY].blot:n?o(t.parentNode,n):null}function i(t,e){void 0===e&&(e=p.ANY);var n;if("string"==typeof t)n=h[t]||u[t];else if(t instanceof Text||t.nodeType===Node.TEXT_NODE)n=h.text;else if("number"==typeof t)t&p.LEVEL&p.BLOCK?n=h.block:t&p.LEVEL&p.INLINE&&(n=h.inline);else if(t instanceof HTMLElement){var r=(t.getAttribute("class")||"").split(/\s+/);for(var o in r)if(n=c[r[o]])break;n=n||f[t.tagName]}return null==n?null:e&p.LEVEL&n.scope&&e&p.TYPE&n.scope?n:null}function l(){for(var t=[],e=0;e1)return t.map(function(t){return l(t)});var n=t[0];if("string"!=typeof n.blotName&&"string"!=typeof n.attrName)throw new s("Invalid definition");if("abstract"===n.blotName)throw new s("Cannot register abstract class");if(h[n.blotName||n.attrName]=n,"string"==typeof n.keyName)u[n.keyName]=n;else if(null!=n.className&&(c[n.className]=n),null!=n.tagName){Array.isArray(n.tagName)?n.tagName=n.tagName.map(function(t){return t.toUpperCase()}):n.tagName=n.tagName.toUpperCase();var r=Array.isArray(n.tagName)?n.tagName:[n.tagName];r.forEach(function(t){null!=f[t]&&null!=n.className||(f[t]=n)})}return n}var a=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var s=function(t){function e(e){var n=this;return e="[Parchment] "+e,n=t.call(this,e)||this,n.message=e,n.name=n.constructor.name,n}return a(e,t),e}(Error);e.ParchmentError=s;var u={},c={},f={},h={};e.DATA_KEY="__blot";var p;!function(t){t[t.TYPE=3]="TYPE",t[t.LEVEL=12]="LEVEL",t[t.ATTRIBUTE=13]="ATTRIBUTE",t[t.BLOT=14]="BLOT",t[t.INLINE=7]="INLINE",t[t.BLOCK=11]="BLOCK",t[t.BLOCK_BLOT=10]="BLOCK_BLOT",t[t.INLINE_BLOT=6]="INLINE_BLOT",t[t.BLOCK_ATTRIBUTE=9]="BLOCK_ATTRIBUTE",t[t.INLINE_ATTRIBUTE=5]="INLINE_ATTRIBUTE",t[t.ANY=15]="ANY"}(p=e.Scope||(e.Scope={})),e.create=r,e.find=o,e.query=i,e.register=l},function(t,e){"use strict";var n=Object.prototype.hasOwnProperty,r=Object.prototype.toString,o=function(t){return"function"==typeof Array.isArray?Array.isArray(t):"[object Array]"===r.call(t)},i=function(t){if(!t||"[object Object]"!==r.call(t))return!1;var e=n.call(t,"constructor"),o=t.constructor&&t.constructor.prototype&&n.call(t.constructor.prototype,"isPrototypeOf");if(t.constructor&&!e&&!o)return!1;var i;for(i in t);return void 0===i||n.call(t,i)};t.exports=function t(){var e,n,r,l,a,s,u=arguments[0],c=1,f=arguments.length,h=!1;for("boolean"==typeof u&&(h=u,u=arguments[1]||{},c=2),(null==u||"object"!=typeof u&&"function"!=typeof u)&&(u={});c1&&void 0!==arguments[1]?arguments[1]:{};return null==t?e:("function"==typeof t.formats&&(e=(0,f.default)(e,t.formats())),null==t.parent||"scroll"==t.parent.blotName||t.parent.statics.scope!==t.statics.scope?e:a(t.parent,e))}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.BlockEmbed=e.bubbleFormats=void 0;var s=function(){function t(t,e){for(var n=0;n0&&(t1&&void 0!==arguments[1]&&arguments[1];if(n&&(0===t||t>=this.length()-1)){var r=this.clone();return 0===t?(this.parent.insertBefore(r,this),this):(this.parent.insertBefore(r,this.next),r)}var o=u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"split",this).call(this,t,n);return this.cache={},o}}]),e}(y.default.Block);x.blotName="block",x.tagName="P",x.defaultChild="break",x.allowedChildren=[m.default,y.default.Embed,O.default],e.bubbleFormats=a,e.BlockEmbed=w,e.default=x},function(t,e,n){var r=n(54),o=n(12),i=n(2),l=n(20),a=String.fromCharCode(0),s=function(t){Array.isArray(t)?this.ops=t:null!=t&&Array.isArray(t.ops)?this.ops=t.ops:this.ops=[]};s.prototype.insert=function(t,e){var n={};return 0===t.length?this:(n.insert=t,null!=e&&"object"==typeof e&&Object.keys(e).length>0&&(n.attributes=e),this.push(n))},s.prototype.delete=function(t){return t<=0?this:this.push({delete:t})},s.prototype.retain=function(t,e){if(t<=0)return this;var n={retain:t};return null!=e&&"object"==typeof e&&Object.keys(e).length>0&&(n.attributes=e),this.push(n)},s.prototype.push=function(t){var e=this.ops.length,n=this.ops[e-1];if(t=i(!0,{},t),"object"==typeof n){if("number"==typeof t.delete&&"number"==typeof n.delete)return this.ops[e-1]={delete:n.delete+t.delete},this;if("number"==typeof n.delete&&null!=t.insert&&(e-=1,"object"!=typeof(n=this.ops[e-1])))return this.ops.unshift(t),this;if(o(t.attributes,n.attributes)){if("string"==typeof t.insert&&"string"==typeof n.insert)return this.ops[e-1]={insert:n.insert+t.insert},"object"==typeof t.attributes&&(this.ops[e-1].attributes=t.attributes),this;if("number"==typeof t.retain&&"number"==typeof n.retain)return this.ops[e-1]={retain:n.retain+t.retain},"object"==typeof t.attributes&&(this.ops[e-1].attributes=t.attributes),this}}return e===this.ops.length?this.ops.push(t):this.ops.splice(e,0,t),this},s.prototype.chop=function(){var t=this.ops[this.ops.length-1];return t&&t.retain&&!t.attributes&&this.ops.pop(),this},s.prototype.filter=function(t){return this.ops.filter(t)},s.prototype.forEach=function(t){this.ops.forEach(t)},s.prototype.map=function(t){return this.ops.map(t)},s.prototype.partition=function(t){var e=[],n=[];return this.forEach(function(r){(t(r)?e:n).push(r)}),[e,n]},s.prototype.reduce=function(t,e){return this.ops.reduce(t,e)},s.prototype.changeLength=function(){return this.reduce(function(t,e){return e.insert?t+l.length(e):e.delete?t-e.delete:t},0)},s.prototype.length=function(){return this.reduce(function(t,e){return t+l.length(e)},0)},s.prototype.slice=function(t,e){t=t||0,"number"!=typeof e&&(e=1/0);for(var n=[],r=l.iterator(this.ops),o=0;o0&&(e.push(t.ops[0]),e.ops=e.ops.concat(t.ops.slice(1))),e},s.prototype.diff=function(t,e){if(this.ops===t.ops)return new s;var n=[this,t].map(function(e){return e.map(function(n){if(null!=n.insert)return"string"==typeof n.insert?n.insert:a;var r=e===t?"on":"with";throw new Error("diff() called "+r+" non-document")}).join("")}),i=new s,u=r(n[0],n[1],e),c=l.iterator(this.ops),f=l.iterator(t.ops);return u.forEach(function(t){for(var e=t[1].length;e>0;){var n=0;switch(t[0]){case r.INSERT:n=Math.min(f.peekLength(),e),i.push(f.next(n));break;case r.DELETE:n=Math.min(e,c.peekLength()),c.next(n),i.delete(n);break;case r.EQUAL:n=Math.min(c.peekLength(),f.peekLength(),e);var a=c.next(n),s=f.next(n);o(a.insert,s.insert)?i.retain(n,l.attributes.diff(a.attributes,s.attributes)):i.push(s).delete(n)}e-=n}}),i.chop()},s.prototype.eachLine=function(t,e){e=e||"\n";for(var n=l.iterator(this.ops),r=new s,o=0;n.hasNext();){if("insert"!==n.peekType())return;var i=n.peek(),a=l.length(i)-n.peekLength(),u="string"==typeof i.insert?i.insert.indexOf(e,a)-a:-1;if(u<0)r.push(n.next());else if(u>0)r.push(n.next(u));else{if(!1===t(r,n.next(1).attributes||{},o))return;o+=1,r=new s}}r.length()>0&&t(r,{},o)},s.prototype.transform=function(t,e){if(e=!!e,"number"==typeof t)return this.transformPosition(t,e);for(var n=l.iterator(this.ops),r=l.iterator(t.ops),o=new s;n.hasNext()||r.hasNext();)if("insert"!==n.peekType()||!e&&"insert"===r.peekType())if("insert"===r.peekType())o.push(r.next());else{var i=Math.min(n.peekLength(),r.peekLength()),a=n.next(i),u=r.next(i);if(a.delete)continue;u.delete?o.push(u):o.retain(i,l.attributes.transform(a.attributes,u.attributes,e))}else o.retain(l.length(n.next()));return o.chop()},s.prototype.transformPosition=function(t,e){e=!!e;for(var n=l.iterator(this.ops),r=0;n.hasNext()&&r<=t;){var o=n.peekLength(),i=n.peekType();n.next(),"delete"!==i?("insert"===i&&(r0){var n=this.parent.isolate(this.offset(),this.length());this.moveChildren(n),n.wrap(this)}}}],[{key:"compare",value:function(t,n){var r=e.order.indexOf(t),o=e.order.indexOf(n);return r>=0||o>=0?r-o:t===n?0:t0){var a,s=[g.default.events.TEXT_CHANGE,l,i,e];if((a=this.emitter).emit.apply(a,[g.default.events.EDITOR_CHANGE].concat(s)),e!==g.default.sources.SILENT){var c;(c=this.emitter).emit.apply(c,s)}}return l}function s(t,e,n,r,o){var i={};return"number"==typeof t.index&&"number"==typeof t.length?"number"!=typeof e?(o=r,r=n,n=e,e=t.length,t=t.index):(e=t.length,t=t.index):"number"!=typeof e&&(o=r,r=n,n=e,e=0),"object"===(void 0===n?"undefined":c(n))?(i=n,o=r):"string"==typeof n&&(null!=r?i[n]=r:o=n),o=o||g.default.sources.API,[t,e,i,o]}function u(t,e,n,r){if(null==t)return null;var o=void 0,i=void 0;if(e instanceof d.default){var l=[t.index,t.index+t.length].map(function(t){return e.transformPosition(t,r!==g.default.sources.USER)}),a=f(l,2);o=a[0],i=a[1]}else{var s=[t.index,t.index+t.length].map(function(t){return t=0?t+n:Math.max(e,t+n)}),u=f(s,2);o=u[0],i=u[1]}return new x.Range(o,i-o)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.overload=e.expandConfig=void 0;var c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},f=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),h=function(){function t(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};if(i(this,t),this.options=l(e,r),this.container=this.options.container,null==this.container)return P.error("Invalid Quill container",e);this.options.debug&&t.debug(this.options.debug);var o=this.container.innerHTML.trim();this.container.classList.add("ql-container"),this.container.innerHTML="",this.container.__quill=this,this.root=this.addContainer("ql-editor"),this.root.classList.add("ql-blank"),this.root.setAttribute("data-gramm",!1),this.scrollingContainer=this.options.scrollingContainer||this.root,this.emitter=new g.default,this.scroll=w.default.create(this.root,{emitter:this.emitter,whitelist:this.options.formats}),this.editor=new v.default(this.scroll),this.selection=new k.default(this.scroll,this.emitter),this.theme=new this.options.theme(this,this.options),this.keyboard=this.theme.addModule("keyboard"),this.clipboard=this.theme.addModule("clipboard"),this.history=this.theme.addModule("history"),this.theme.init(),this.emitter.on(g.default.events.EDITOR_CHANGE,function(t){t===g.default.events.TEXT_CHANGE&&n.root.classList.toggle("ql-blank",n.editor.isBlank())}),this.emitter.on(g.default.events.SCROLL_UPDATE,function(t,e){var r=n.selection.lastRange,o=r&&0===r.length?r.index:void 0;a.call(n,function(){return n.editor.update(null,e,o)},t)});var s=this.clipboard.convert("
"+o+"


");this.setContents(s),this.history.clear(),this.options.placeholder&&this.root.setAttribute("data-placeholder",this.options.placeholder),this.options.readOnly&&this.disable()}return h(t,null,[{key:"debug",value:function(t){!0===t&&(t="log"),A.default.level(t)}},{key:"find",value:function(t){return t.__quill||w.default.find(t)}},{key:"import",value:function(t){return null==this.imports[t]&&P.error("Cannot import "+t+". Are you sure it was registered?"),this.imports[t]}},{key:"register",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if("string"!=typeof t){var o=t.attrName||t.blotName;"string"==typeof o?this.register("formats/"+o,t,e):Object.keys(t).forEach(function(r){n.register(r,t[r],e)})}else null==this.imports[t]||r||P.warn("Overwriting "+t+" with",e),this.imports[t]=e,(t.startsWith("blots/")||t.startsWith("formats/"))&&"abstract"!==e.blotName?w.default.register(e):t.startsWith("modules")&&"function"==typeof e.register&&e.register()}}]),h(t,[{key:"addContainer",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if("string"==typeof t){var n=t;t=document.createElement("div"),t.classList.add(n)}return this.container.insertBefore(t,e),t}},{key:"blur",value:function(){this.selection.setRange(null)}},{key:"deleteText",value:function(t,e,n){var r=this,o=s(t,e,n),i=f(o,4);return t=i[0],e=i[1],n=i[3],a.call(this,function(){return r.editor.deleteText(t,e)},n,t,-1*e)}},{key:"disable",value:function(){this.enable(!1)}},{key:"enable",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.scroll.enable(t),this.container.classList.toggle("ql-disabled",!t)}},{key:"focus",value:function(){var t=this.scrollingContainer.scrollTop;this.selection.focus(),this.scrollingContainer.scrollTop=t,this.scrollIntoView()}},{key:"format",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:g.default.sources.API;return a.call(this,function(){var r=n.getSelection(!0),i=new d.default;if(null==r)return i;if(w.default.query(t,w.default.Scope.BLOCK))i=n.editor.formatLine(r.index,r.length,o({},t,e));else{if(0===r.length)return n.selection.format(t,e),i;i=n.editor.formatText(r.index,r.length,o({},t,e))}return n.setSelection(r,g.default.sources.SILENT),i},r)}},{key:"formatLine",value:function(t,e,n,r,o){var i=this,l=void 0,u=s(t,e,n,r,o),c=f(u,4);return t=c[0],e=c[1],l=c[2],o=c[3],a.call(this,function(){return i.editor.formatLine(t,e,l)},o,t,0)}},{key:"formatText",value:function(t,e,n,r,o){var i=this,l=void 0,u=s(t,e,n,r,o),c=f(u,4);return t=c[0],e=c[1],l=c[2],o=c[3],a.call(this,function(){return i.editor.formatText(t,e,l)},o,t,0)}},{key:"getBounds",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=void 0;n="number"==typeof t?this.selection.getBounds(t,e):this.selection.getBounds(t.index,t.length);var r=this.container.getBoundingClientRect();return{bottom:n.bottom-r.top,height:n.height,left:n.left-r.left,right:n.right-r.left,top:n.top-r.top,width:n.width}}},{key:"getContents",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.getLength()-t,n=s(t,e),r=f(n,2);return t=r[0],e=r[1],this.editor.getContents(t,e)}},{key:"getFormat",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.getSelection(!0),e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return"number"==typeof t?this.editor.getFormat(t,e):this.editor.getFormat(t.index,t.length)}},{key:"getIndex",value:function(t){return t.offset(this.scroll)}},{key:"getLength",value:function(){return this.scroll.length()}},{key:"getLeaf",value:function(t){return this.scroll.leaf(t)}},{key:"getLine",value:function(t){return this.scroll.line(t)}},{key:"getLines",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Number.MAX_VALUE;return"number"!=typeof t?this.scroll.lines(t.index,t.length):this.scroll.lines(t,e)}},{key:"getModule",value:function(t){return this.theme.modules[t]}},{key:"getSelection",value:function(){return arguments.length>0&&void 0!==arguments[0]&&arguments[0]&&this.focus(),this.update(),this.selection.getRange()[0]}},{key:"getText",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.getLength()-t,n=s(t,e),r=f(n,2);return t=r[0],e=r[1],this.editor.getText(t,e)}},{key:"hasFocus",value:function(){return this.selection.hasFocus()}},{key:"insertEmbed",value:function(e,n,r){var o=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:t.sources.API;return a.call(this,function(){return o.editor.insertEmbed(e,n,r)},i,e)}},{key:"insertText",value:function(t,e,n,r,o){var i=this,l=void 0,u=s(t,0,n,r,o),c=f(u,4);return t=c[0],l=c[2],o=c[3],a.call(this,function(){return i.editor.insertText(t,e,l)},o,t,e.length)}},{key:"isEnabled",value:function(){return!this.container.classList.contains("ql-disabled")}},{key:"off",value:function(){return this.emitter.off.apply(this.emitter,arguments)}},{key:"on",value:function(){return this.emitter.on.apply(this.emitter,arguments)}},{key:"once",value:function(){return this.emitter.once.apply(this.emitter,arguments)}},{key:"pasteHTML",value:function(t,e,n){this.clipboard.dangerouslyPasteHTML(t,e,n)}},{key:"removeFormat",value:function(t,e,n){var r=this,o=s(t,e,n),i=f(o,4);return t=i[0],e=i[1],n=i[3],a.call(this,function(){return r.editor.removeFormat(t,e)},n,t)}},{key:"scrollIntoView",value:function(){this.selection.scrollIntoView(this.scrollingContainer)}},{key:"setContents",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:g.default.sources.API;return a.call(this,function(){t=new d.default(t);var n=e.getLength(),r=e.editor.deleteText(0,n),o=e.editor.applyDelta(t),i=o.ops[o.ops.length-1];return null!=i&&"string"==typeof i.insert&&"\n"===i.insert[i.insert.length-1]&&(e.editor.deleteText(e.getLength()-1,1),o.delete(1)),r.compose(o)},n)}},{key:"setSelection",value:function(e,n,r){if(null==e)this.selection.setRange(null,n||t.sources.API);else{var o=s(e,n,r),i=f(o,4);e=i[0],n=i[1],r=i[3],this.selection.setRange(new x.Range(e,n),r),r!==g.default.sources.SILENT&&this.selection.scrollIntoView(this.scrollingContainer)}}},{key:"setText",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:g.default.sources.API,n=(new d.default).insert(t);return this.setContents(n,e)}},{key:"update",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:g.default.sources.USER,e=this.scroll.update(t);return this.selection.update(t),e}},{key:"updateContents",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:g.default.sources.API;return a.call(this,function(){return t=new d.default(t),e.editor.applyDelta(t,n)},n,!0)}}]),t}();S.DEFAULTS={bounds:null,formats:null,modules:{},placeholder:"",readOnly:!1,scrollingContainer:null,strict:!0,theme:"default"},S.events=g.default.events,S.sources=g.default.sources,S.version="1.3.6",S.imports={delta:d.default,parchment:w.default,"core/module":_.default,"core/theme":T.default},e.expandConfig=l,e.overload=s,e.default=S},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var o=function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};r(this,t),this.quill=e,this.options=n};o.DEFAULTS={},e.default=o},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=n(0),a=function(t){return t&&t.__esModule?t:{default:t}}(l),s=function(t){function e(){return r(this,e),o(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return i(e,t),e}(a.default.Text);e.default=s},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(t,e){for(var n=0;n1?e-1:0),r=1;r1?n-1:0),o=1;o-1:this.whitelist.indexOf(e)>-1))},t.prototype.remove=function(t){t.removeAttribute(this.keyName)},t.prototype.value=function(t){var e=t.getAttribute(this.keyName);return this.canAdd(t,e)&&e?e:""},t}();e.default=o},function(t,e,n){function r(t){return null===t||void 0===t}function o(t){return!(!t||"object"!=typeof t||"number"!=typeof t.length)&&("function"==typeof t.copy&&"function"==typeof t.slice&&!(t.length>0&&"number"!=typeof t[0]))}function i(t,e,n){var i,c;if(r(t)||r(e))return!1;if(t.prototype!==e.prototype)return!1;if(s(t))return!!s(e)&&(t=l.call(t),e=l.call(e),u(t,e,n));if(o(t)){if(!o(e))return!1;if(t.length!==e.length)return!1;for(i=0;i=0;i--)if(f[i]!=h[i])return!1;for(i=f.length-1;i>=0;i--)if(c=f[i],!u(t[c],e[c],n))return!1;return typeof t==typeof e}var l=Array.prototype.slice,a=n(55),s=n(56),u=t.exports=function(t,e,n){return n||(n={}),t===e||(t instanceof Date&&e instanceof Date?t.getTime()===e.getTime():!t||!e||"object"!=typeof t&&"object"!=typeof e?n.strict?t===e:t==e:i(t,e,n))}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.Code=void 0;var a=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),s=function(){function t(t,e){for(var n=0;n=t+n)){var l=this.newlineIndex(t,!0)+1,a=i-l+1,s=this.isolate(l,a),u=s.next;s.format(r,o),u instanceof e&&u.formatAt(0,t-l+n-a,r,o)}}}},{key:"insertAt",value:function(t,e,n){if(null==n){var r=this.descendant(m.default,t),o=a(r,2),i=o[0],l=o[1];i.insertAt(l,e)}}},{key:"length",value:function(){var t=this.domNode.textContent.length;return this.domNode.textContent.endsWith("\n")?t:t+1}},{key:"newlineIndex",value:function(t){if(arguments.length>1&&void 0!==arguments[1]&&arguments[1])return this.domNode.textContent.slice(0,t).lastIndexOf("\n");var e=this.domNode.textContent.slice(t).indexOf("\n");return e>-1?t+e:-1}},{key:"optimize",value:function(t){this.domNode.textContent.endsWith("\n")||this.appendChild(p.default.create("text","\n")),u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"optimize",this).call(this,t);var n=this.next;null!=n&&n.prev===this&&n.statics.blotName===this.statics.blotName&&this.statics.formats(this.domNode)===n.statics.formats(n.domNode)&&(n.optimize(t),n.moveChildren(this),n.remove())}},{key:"replace",value:function(t){u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"replace",this).call(this,t),[].slice.call(this.domNode.querySelectorAll("*")).forEach(function(t){var e=p.default.find(t);null==e?t.parentNode.removeChild(t):e instanceof p.default.Embed?e.remove():e.unwrap()})}}],[{key:"create",value:function(t){var n=u(e.__proto__||Object.getPrototypeOf(e),"create",this).call(this,t);return n.setAttribute("spellcheck",!1),n}},{key:"formats",value:function(){return!0}}]),e}(y.default);O.blotName="code-block",O.tagName="PRE",O.TAB=" ",e.Code=_,e.default=O},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;n-1}Object.defineProperty(e,"__esModule",{value:!0}),e.sanitize=e.default=void 0;var a=function(){function t(t,e){for(var n=0;n1&&void 0!==arguments[1]&&arguments[1],n=this.container.querySelector(".ql-selected");if(t!==n&&(null!=n&&n.classList.remove("ql-selected"),null!=t&&(t.classList.add("ql-selected"),this.select.selectedIndex=[].indexOf.call(t.parentNode.children,t),t.hasAttribute("data-value")?this.label.setAttribute("data-value",t.getAttribute("data-value")):this.label.removeAttribute("data-value"),t.hasAttribute("data-label")?this.label.setAttribute("data-label",t.getAttribute("data-label")):this.label.removeAttribute("data-label"),e))){if("function"==typeof Event)this.select.dispatchEvent(new Event("change"));else if("object"===("undefined"==typeof Event?"undefined":l(Event))){var r=document.createEvent("Event");r.initEvent("change",!0,!0),this.select.dispatchEvent(r)}this.close()}}},{key:"update",value:function(){var t=void 0;if(this.select.selectedIndex>-1){var e=this.container.querySelector(".ql-picker-options").children[this.select.selectedIndex];t=this.select.options[this.select.selectedIndex],this.selectItem(e)}else this.selectItem(null);var n=null!=t&&t!==this.select.querySelector("option[selected]");this.label.classList.toggle("ql-active",n)}}]),t}();e.default=p},function(t,e,n){"use strict";function r(t){var e=a.find(t);if(null==e)try{e=a.create(t)}catch(n){e=a.create(a.Scope.INLINE),[].slice.call(t.childNodes).forEach(function(t){e.domNode.appendChild(t)}),t.parentNode&&t.parentNode.replaceChild(e.domNode,t),e.attach()}return e}var o=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var i=n(47),l=n(27),a=n(1),s=function(t){function e(e){var n=t.call(this,e)||this;return n.build(),n}return o(e,t),e.prototype.appendChild=function(t){this.insertBefore(t)},e.prototype.attach=function(){t.prototype.attach.call(this),this.children.forEach(function(t){t.attach()})},e.prototype.build=function(){var t=this;this.children=new i.default,[].slice.call(this.domNode.childNodes).reverse().forEach(function(e){try{var n=r(e);t.insertBefore(n,t.children.head||void 0)}catch(t){if(t instanceof a.ParchmentError)return;throw t}})},e.prototype.deleteAt=function(t,e){if(0===t&&e===this.length())return this.remove();this.children.forEachAt(t,e,function(t,e,n){t.deleteAt(e,n)})},e.prototype.descendant=function(t,n){var r=this.children.find(n),o=r[0],i=r[1];return null==t.blotName&&t(o)||null!=t.blotName&&o instanceof t?[o,i]:o instanceof e?o.descendant(t,i):[null,-1]},e.prototype.descendants=function(t,n,r){void 0===n&&(n=0),void 0===r&&(r=Number.MAX_VALUE);var o=[],i=r;return this.children.forEachAt(n,r,function(n,r,l){(null==t.blotName&&t(n)||null!=t.blotName&&n instanceof t)&&o.push(n),n instanceof e&&(o=o.concat(n.descendants(t,r,i))),i-=l}),o},e.prototype.detach=function(){this.children.forEach(function(t){t.detach()}),t.prototype.detach.call(this)},e.prototype.formatAt=function(t,e,n,r){this.children.forEachAt(t,e,function(t,e,o){t.formatAt(e,o,n,r)})},e.prototype.insertAt=function(t,e,n){var r=this.children.find(t),o=r[0],i=r[1];if(o)o.insertAt(i,e,n);else{var l=null==n?a.create("text",e):a.create(e,n);this.appendChild(l)}},e.prototype.insertBefore=function(t,e){if(null!=this.statics.allowedChildren&&!this.statics.allowedChildren.some(function(e){return t instanceof e}))throw new a.ParchmentError("Cannot insert "+t.statics.blotName+" into "+this.statics.blotName);t.insertInto(this,e)},e.prototype.length=function(){return this.children.reduce(function(t,e){return t+e.length()},0)},e.prototype.moveChildren=function(t,e){this.children.forEach(function(n){t.insertBefore(n,e)})},e.prototype.optimize=function(e){if(t.prototype.optimize.call(this,e),0===this.children.length)if(null!=this.statics.defaultChild){var n=a.create(this.statics.defaultChild);this.appendChild(n),n.optimize(e)}else this.remove()},e.prototype.path=function(t,n){void 0===n&&(n=!1);var r=this.children.find(t,n),o=r[0],i=r[1],l=[[this,t]];return o instanceof e?l.concat(o.path(i,n)):(null!=o&&l.push([o,i]),l)},e.prototype.removeChild=function(t){this.children.remove(t)},e.prototype.replace=function(n){n instanceof e&&n.moveChildren(this),t.prototype.replace.call(this,n)},e.prototype.split=function(t,e){if(void 0===e&&(e=!1),!e){if(0===t)return this;if(t===this.length())return this.next}var n=this.clone();return this.parent.insertBefore(n,this.next),this.children.forEachAt(t,this.length(),function(t,r,o){t=t.split(r,e),n.appendChild(t)}),n},e.prototype.unwrap=function(){this.moveChildren(this.parent,this.next),this.remove()},e.prototype.update=function(t,e){var n=this,o=[],i=[];t.forEach(function(t){t.target===n.domNode&&"childList"===t.type&&(o.push.apply(o,t.addedNodes),i.push.apply(i,t.removedNodes))}),i.forEach(function(t){if(!(null!=t.parentNode&&"IFRAME"!==t.tagName&&document.body.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_CONTAINED_BY)){var e=a.find(t);null!=e&&(null!=e.domNode.parentNode&&e.domNode.parentNode!==n.domNode||e.detach())}}),o.filter(function(t){return t.parentNode==n.domNode}).sort(function(t,e){return t===e?0:t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING?1:-1}).forEach(function(t){var e=null;null!=t.nextSibling&&(e=a.find(t.nextSibling));var o=r(t);o.next==e&&null!=o.next||(null!=o.parent&&o.parent.removeChild(n),n.insertBefore(o,e||void 0))})},e}(l.default);e.default=s},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(11),i=n(28),l=n(17),a=n(1),s=function(t){function e(e){var n=t.call(this,e)||this;return n.attributes=new i.default(n.domNode),n}return r(e,t),e.formats=function(t){return"string"==typeof this.tagName||(Array.isArray(this.tagName)?t.tagName.toLowerCase():void 0)},e.prototype.format=function(t,e){var n=a.query(t);n instanceof o.default?this.attributes.attribute(n,e):e&&(null==n||t===this.statics.blotName&&this.formats()[t]===e||this.replaceWith(t,e))},e.prototype.formats=function(){var t=this.attributes.values(),e=this.statics.formats(this.domNode);return null!=e&&(t[this.statics.blotName]=e),t},e.prototype.replaceWith=function(e,n){var r=t.prototype.replaceWith.call(this,e,n);return this.attributes.copy(r),r},e.prototype.update=function(e,n){var r=this;t.prototype.update.call(this,e,n),e.some(function(t){return t.target===r.domNode&&"attributes"===t.type})&&this.attributes.build()},e.prototype.wrap=function(n,r){var o=t.prototype.wrap.call(this,n,r);return o instanceof e&&o.statics.scope===this.statics.scope&&this.attributes.move(o),o},e}(l.default);e.default=s},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(27),i=n(1),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return r(e,t),e.value=function(t){return!0},e.prototype.index=function(t,e){return this.domNode===t||this.domNode.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_CONTAINED_BY?Math.min(e,1):-1},e.prototype.position=function(t,e){var n=[].indexOf.call(this.parent.domNode.childNodes,this.domNode);return t>0&&(n+=1),[this.parent.domNode,n]},e.prototype.value=function(){return t={},t[this.statics.blotName]=this.statics.value(this.domNode)||!0,t;var t},e.scope=i.Scope.INLINE_BLOT,e}(o.default);e.default=l},function(t,e,n){function r(t){this.ops=t,this.index=0,this.offset=0}var o=n(12),i=n(2),l={attributes:{compose:function(t,e,n){"object"!=typeof t&&(t={}),"object"!=typeof e&&(e={});var r=i(!0,{},e);n||(r=Object.keys(r).reduce(function(t,e){return null!=r[e]&&(t[e]=r[e]),t},{}));for(var o in t)void 0!==t[o]&&void 0===e[o]&&(r[o]=t[o]);return Object.keys(r).length>0?r:void 0},diff:function(t,e){"object"!=typeof t&&(t={}),"object"!=typeof e&&(e={});var n=Object.keys(t).concat(Object.keys(e)).reduce(function(n,r){return o(t[r],e[r])||(n[r]=void 0===e[r]?null:e[r]),n},{});return Object.keys(n).length>0?n:void 0},transform:function(t,e,n){if("object"!=typeof t)return e;if("object"==typeof e){if(!n)return e;var r=Object.keys(e).reduce(function(n,r){return void 0===t[r]&&(n[r]=e[r]),n},{});return Object.keys(r).length>0?r:void 0}}},iterator:function(t){return new r(t)},length:function(t){return"number"==typeof t.delete?t.delete:"number"==typeof t.retain?t.retain:"string"==typeof t.insert?t.insert.length:1}};r.prototype.hasNext=function(){return this.peekLength()<1/0},r.prototype.next=function(t){t||(t=1/0);var e=this.ops[this.index];if(e){var n=this.offset,r=l.length(e);if(t>=r-n?(t=r-n,this.index+=1,this.offset=0):this.offset+=t,"number"==typeof e.delete)return{delete:t};var o={};return e.attributes&&(o.attributes=e.attributes),"number"==typeof e.retain?o.retain=t:"string"==typeof e.insert?o.insert=e.insert.substr(n,t):o.insert=e.insert,o}return{retain:1/0}},r.prototype.peek=function(){return this.ops[this.index]},r.prototype.peekLength=function(){return this.ops[this.index]?l.length(this.ops[this.index])-this.offset:1/0},r.prototype.peekType=function(){return this.ops[this.index]?"number"==typeof this.ops[this.index].delete?"delete":"number"==typeof this.ops[this.index].retain?"retain":"insert":"retain"},t.exports=l},function(t,e){var n=function(){"use strict";function t(t,e){return null!=e&&t instanceof e}function e(n,r,o,i,c){function f(n,o){if(null===n)return null;if(0===o)return n;var y,v;if("object"!=typeof n)return n;if(t(n,a))y=new a;else if(t(n,s))y=new s;else if(t(n,u))y=new u(function(t,e){n.then(function(e){t(f(e,o-1))},function(t){e(f(t,o-1))})});else if(e.__isArray(n))y=[];else if(e.__isRegExp(n))y=new RegExp(n.source,l(n)),n.lastIndex&&(y.lastIndex=n.lastIndex);else if(e.__isDate(n))y=new Date(n.getTime());else{if(d&&Buffer.isBuffer(n))return y=new Buffer(n.length),n.copy(y),y;t(n,Error)?y=Object.create(n):void 0===i?(v=Object.getPrototypeOf(n),y=Object.create(v)):(y=Object.create(i),v=i)}if(r){var b=h.indexOf(n);if(-1!=b)return p[b];h.push(n),p.push(y)}t(n,a)&&n.forEach(function(t,e){var n=f(e,o-1),r=f(t,o-1);y.set(n,r)}),t(n,s)&&n.forEach(function(t){var e=f(t,o-1);y.add(e)});for(var g in n){var m;v&&(m=Object.getOwnPropertyDescriptor(v,g)),m&&null==m.set||(y[g]=f(n[g],o-1))}if(Object.getOwnPropertySymbols)for(var _=Object.getOwnPropertySymbols(n),g=0;g<_.length;g++){var O=_[g],w=Object.getOwnPropertyDescriptor(n,O);(!w||w.enumerable||c)&&(y[O]=f(n[O],o-1),w.enumerable||Object.defineProperty(y,O,{enumerable:!1}))}if(c)for(var x=Object.getOwnPropertyNames(n),g=0;g1&&void 0!==arguments[1]?arguments[1]:0;i(this,t),this.index=e,this.length=n},O=function(){function t(e,n){var r=this;i(this,t),this.emitter=n,this.scroll=e,this.composing=!1,this.mouseDown=!1,this.root=this.scroll.domNode,this.cursor=c.default.create("cursor",this),this.lastRange=this.savedRange=new _(0,0),this.handleComposition(),this.handleDragging(),this.emitter.listenDOM("selectionchange",document,function(){r.mouseDown||setTimeout(r.update.bind(r,v.default.sources.USER),1)}),this.emitter.on(v.default.events.EDITOR_CHANGE,function(t,e){t===v.default.events.TEXT_CHANGE&&e.length()>0&&r.update(v.default.sources.SILENT)}),this.emitter.on(v.default.events.SCROLL_BEFORE_UPDATE,function(){if(r.hasFocus()){var t=r.getNativeRange();null!=t&&t.start.node!==r.cursor.textNode&&r.emitter.once(v.default.events.SCROLL_UPDATE,function(){try{r.setNativeRange(t.start.node,t.start.offset,t.end.node,t.end.offset)}catch(t){}})}}),this.emitter.on(v.default.events.SCROLL_OPTIMIZE,function(t,e){if(e.range){var n=e.range,o=n.startNode,i=n.startOffset,l=n.endNode,a=n.endOffset;r.setNativeRange(o,i,l,a)}}),this.update(v.default.sources.SILENT)}return s(t,[{key:"handleComposition",value:function(){var t=this;this.root.addEventListener("compositionstart",function(){t.composing=!0}),this.root.addEventListener("compositionend",function(){if(t.composing=!1,t.cursor.parent){var e=t.cursor.restore();if(!e)return;setTimeout(function(){t.setNativeRange(e.startNode,e.startOffset,e.endNode,e.endOffset)},1)}})}},{key:"handleDragging",value:function(){var t=this;this.emitter.listenDOM("mousedown",document.body,function(){t.mouseDown=!0}),this.emitter.listenDOM("mouseup",document.body,function(){t.mouseDown=!1,t.update(v.default.sources.USER)})}},{key:"focus",value:function(){this.hasFocus()||(this.root.focus(),this.setRange(this.savedRange))}},{key:"format",value:function(t,e){if(null==this.scroll.whitelist||this.scroll.whitelist[t]){this.scroll.update();var n=this.getNativeRange();if(null!=n&&n.native.collapsed&&!c.default.query(t,c.default.Scope.BLOCK)){if(n.start.node!==this.cursor.textNode){var r=c.default.find(n.start.node,!1);if(null==r)return;if(r instanceof c.default.Leaf){var o=r.split(n.start.offset);r.parent.insertBefore(this.cursor,o)}else r.insertBefore(this.cursor,n.start.node);this.cursor.attach()}this.cursor.format(t,e),this.scroll.optimize(),this.setNativeRange(this.cursor.textNode,this.cursor.textNode.data.length),this.update()}}}},{key:"getBounds",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=this.scroll.length();t=Math.min(t,n-1),e=Math.min(t+e,n-1)-t;var r=void 0,o=this.scroll.leaf(t),i=a(o,2),l=i[0],s=i[1];if(null==l)return null;var u=l.position(s,!0),c=a(u,2);r=c[0],s=c[1];var f=document.createRange();if(e>0){f.setStart(r,s);var h=this.scroll.leaf(t+e),p=a(h,2);if(l=p[0],s=p[1],null==l)return null;var d=l.position(s,!0),y=a(d,2);return r=y[0],s=y[1],f.setEnd(r,s),f.getBoundingClientRect()}var v="left",b=void 0;return r instanceof Text?(s0&&(v="right")),{bottom:b.top+b.height,height:b.height,left:b[v],right:b[v],top:b.top,width:0}}},{key:"getNativeRange",value:function(){var t=document.getSelection();if(null==t||t.rangeCount<=0)return null;var e=t.getRangeAt(0);if(null==e)return null;var n=this.normalizeNative(e);return m.info("getNativeRange",n),n}},{key:"getRange",value:function(){var t=this.getNativeRange();return null==t?[null,null]:[this.normalizedToRange(t),t]}},{key:"hasFocus",value:function(){return document.activeElement===this.root}},{key:"normalizedToRange",value:function(t){var e=this,n=[[t.start.node,t.start.offset]];t.native.collapsed||n.push([t.end.node,t.end.offset]);var r=n.map(function(t){var n=a(t,2),r=n[0],o=n[1],i=c.default.find(r,!0),l=i.offset(e.scroll);return 0===o?l:i instanceof c.default.Container?l+i.length():l+i.index(r,o)}),i=Math.min(Math.max.apply(Math,o(r)),this.scroll.length()-1),l=Math.min.apply(Math,[i].concat(o(r)));return new _(l,i-l)}},{key:"normalizeNative",value:function(t){if(!l(this.root,t.startContainer)||!t.collapsed&&!l(this.root,t.endContainer))return null;var e={start:{node:t.startContainer,offset:t.startOffset},end:{node:t.endContainer,offset:t.endOffset},native:t};return[e.start,e.end].forEach(function(t){for(var e=t.node,n=t.offset;!(e instanceof Text)&&e.childNodes.length>0;)if(e.childNodes.length>n)e=e.childNodes[n],n=0;else{if(e.childNodes.length!==n)break;e=e.lastChild,n=e instanceof Text?e.data.length:e.childNodes.length+1}t.node=e,t.offset=n}),e}},{key:"rangeToNative",value:function(t){var e=this,n=t.collapsed?[t.index]:[t.index,t.index+t.length],r=[],o=this.scroll.length();return n.forEach(function(t,n){t=Math.min(o-1,t);var i=void 0,l=e.scroll.leaf(t),s=a(l,2),u=s[0],c=s[1],f=u.position(c,0!==n),h=a(f,2);i=h[0],c=h[1],r.push(i,c)}),r.length<2&&(r=r.concat(r)),r}},{key:"scrollIntoView",value:function(t){var e=this.lastRange;if(null!=e){var n=this.getBounds(e.index,e.length);if(null!=n){var r=this.scroll.length()-1,o=this.scroll.line(Math.min(e.index,r)),i=a(o,1),l=i[0],s=l;if(e.length>0){var u=this.scroll.line(Math.min(e.index+e.length,r));s=a(u,1)[0]}if(null!=l&&null!=s){var c=t.getBoundingClientRect();n.topc.bottom&&(t.scrollTop+=n.bottom-c.bottom)}}}}},{key:"setNativeRange",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:e,o=arguments.length>4&&void 0!==arguments[4]&&arguments[4];if(m.info("setNativeRange",t,e,n,r),null==t||null!=this.root.parentNode&&null!=t.parentNode&&null!=n.parentNode){var i=document.getSelection();if(null!=i)if(null!=t){this.hasFocus()||this.root.focus();var l=(this.getNativeRange()||{}).native;if(null==l||o||t!==l.startContainer||e!==l.startOffset||n!==l.endContainer||r!==l.endOffset){"BR"==t.tagName&&(e=[].indexOf.call(t.parentNode.childNodes,t),t=t.parentNode),"BR"==n.tagName&&(r=[].indexOf.call(n.parentNode.childNodes,n),n=n.parentNode);var a=document.createRange();a.setStart(t,e),a.setEnd(n,r),i.removeAllRanges(),i.addRange(a)}}else i.removeAllRanges(),this.root.blur(),document.body.focus()}}},{key:"setRange",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:v.default.sources.API;if("string"==typeof e&&(n=e,e=!1),m.info("setRange",t),null!=t){var r=this.rangeToNative(t);this.setNativeRange.apply(this,o(r).concat([e]))}else this.setNativeRange(null);this.update(n)}},{key:"update",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:v.default.sources.USER,e=this.lastRange,n=this.getRange(),r=a(n,2),o=r[0],i=r[1];if(this.lastRange=o,null!=this.lastRange&&(this.savedRange=this.lastRange),!(0,d.default)(e,this.lastRange)){var l;!this.composing&&null!=i&&i.native.collapsed&&i.start.node!==this.cursor.textNode&&this.cursor.restore();var s=[v.default.events.SELECTION_CHANGE,(0,h.default)(this.lastRange),(0,h.default)(e),t];if((l=this.emitter).emit.apply(l,[v.default.events.EDITOR_CHANGE].concat(s)),t!==v.default.sources.SILENT){var u;(u=this.emitter).emit.apply(u,s)}}}}]),t}();e.Range=_,e.default=O},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var a=n(0),s=r(a),u=n(3),c=r(u),f=function(t){function e(){return o(this,e),i(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return l(e,t),e}(s.default.Container);f.allowedChildren=[c.default,u.BlockEmbed,f],e.default=f},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.ColorStyle=e.ColorClass=e.ColorAttributor=void 0;var l=function(){function t(t,e){for(var n=0;n1){var u=o.formats(),c=this.quill.getFormat(t.index-1,1);i=A.default.attributes.diff(u,c)||{}}}var f=/[\uD800-\uDBFF][\uDC00-\uDFFF]$/.test(e.prefix)?2:1;this.quill.deleteText(t.index-f,f,S.default.sources.USER),Object.keys(i).length>0&&this.quill.formatLine(t.index-f,f,i,S.default.sources.USER),this.quill.focus()}}function c(t,e){var n=/^[\uD800-\uDBFF][\uDC00-\uDFFF]/.test(e.suffix)?2:1;if(!(t.index>=this.quill.getLength()-n)){var r={},o=0,i=this.quill.getLine(t.index),l=b(i,1),a=l[0];if(e.offset>=a.length()-1){var s=this.quill.getLine(t.index+1),u=b(s,1),c=u[0];if(c){var f=a.formats(),h=this.quill.getFormat(t.index,1);r=A.default.attributes.diff(f,h)||{},o=c.length()}}this.quill.deleteText(t.index,n,S.default.sources.USER),Object.keys(r).length>0&&this.quill.formatLine(t.index+o-1,n,r,S.default.sources.USER)}}function f(t){var e=this.quill.getLines(t),n={};if(e.length>1){var r=e[0].formats(),o=e[e.length-1].formats();n=A.default.attributes.diff(o,r)||{}}this.quill.deleteText(t,S.default.sources.USER),Object.keys(n).length>0&&this.quill.formatLine(t.index,1,n,S.default.sources.USER),this.quill.setSelection(t.index,S.default.sources.SILENT),this.quill.focus()}function h(t,e){var n=this;t.length>0&&this.quill.scroll.deleteAt(t.index,t.length);var r=Object.keys(e.format).reduce(function(t,n){return T.default.query(n,T.default.Scope.BLOCK)&&!Array.isArray(e.format[n])&&(t[n]=e.format[n]),t},{});this.quill.insertText(t.index,"\n",r,S.default.sources.USER),this.quill.setSelection(t.index+1,S.default.sources.SILENT),this.quill.focus(),Object.keys(e.format).forEach(function(t){null==r[t]&&(Array.isArray(e.format[t])||"link"!==t&&n.quill.format(t,e.format[t],S.default.sources.USER))})}function p(t){return{key:D.keys.TAB,shiftKey:!t,format:{"code-block":!0},handler:function(e){var n=T.default.query("code-block"),r=e.index,o=e.length,i=this.quill.scroll.descendant(n,r),l=b(i,2),a=l[0],s=l[1];if(null!=a){var u=this.quill.getIndex(a),c=a.newlineIndex(s,!0)+1,f=a.newlineIndex(u+s+o),h=a.domNode.textContent.slice(c,f).split("\n");s=0,h.forEach(function(e,i){t?(a.insertAt(c+s,n.TAB),s+=n.TAB.length,0===i?r+=n.TAB.length:o+=n.TAB.length):e.startsWith(n.TAB)&&(a.deleteAt(c+s,n.TAB.length),s-=n.TAB.length,0===i?r-=n.TAB.length:o-=n.TAB.length),s+=e.length+1}),this.quill.update(S.default.sources.USER),this.quill.setSelection(r,o,S.default.sources.SILENT)}}}}function d(t){return{key:t[0].toUpperCase(),shortKey:!0,handler:function(e,n){this.quill.format(t,!n.format[t],S.default.sources.USER)}}}function y(t){if("string"==typeof t||"number"==typeof t)return y({key:t});if("object"===(void 0===t?"undefined":v(t))&&(t=(0,_.default)(t,!1)),"string"==typeof t.key)if(null!=D.keys[t.key.toUpperCase()])t.key=D.keys[t.key.toUpperCase()];else{if(1!==t.key.length)return null;t.key=t.key.toUpperCase().charCodeAt(0)}return t.shortKey&&(t[B]=t.shortKey,delete t.shortKey),t}Object.defineProperty(e,"__esModule",{value:!0}),e.SHORTKEY=e.default=void 0;var v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},b=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),g=function(){function t(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=y(t);if(null==r||null==r.key)return I.warn("Attempted to add invalid keyboard binding",r);"function"==typeof e&&(e={handler:e}),"function"==typeof n&&(n={handler:n}),r=(0,k.default)(r,e,n),this.bindings[r.key]=this.bindings[r.key]||[],this.bindings[r.key].push(r)}},{key:"listen",value:function(){var t=this;this.quill.root.addEventListener("keydown",function(n){if(!n.defaultPrevented){var r=n.which||n.keyCode,o=(t.bindings[r]||[]).filter(function(t){return e.match(n,t)});if(0!==o.length){var i=t.quill.getSelection();if(null!=i&&t.quill.hasFocus()){var l=t.quill.getLine(i.index),a=b(l,2),s=a[0],u=a[1],c=t.quill.getLeaf(i.index),f=b(c,2),h=f[0],p=f[1],d=0===i.length?[h,p]:t.quill.getLeaf(i.index+i.length),y=b(d,2),g=y[0],m=y[1],_=h instanceof T.default.Text?h.value().slice(0,p):"",O=g instanceof T.default.Text?g.value().slice(m):"",x={collapsed:0===i.length,empty:0===i.length&&s.length()<=1,format:t.quill.getFormat(i),offset:u,prefix:_,suffix:O};o.some(function(e){if(null!=e.collapsed&&e.collapsed!==x.collapsed)return!1;if(null!=e.empty&&e.empty!==x.empty)return!1;if(null!=e.offset&&e.offset!==x.offset)return!1;if(Array.isArray(e.format)){if(e.format.every(function(t){return null==x.format[t]}))return!1}else if("object"===v(e.format)&&!Object.keys(e.format).every(function(t){return!0===e.format[t]?null!=x.format[t]:!1===e.format[t]?null==x.format[t]:(0,w.default)(e.format[t],x.format[t])}))return!1;return!(null!=e.prefix&&!e.prefix.test(x.prefix))&&(!(null!=e.suffix&&!e.suffix.test(x.suffix))&&!0!==e.handler.call(t,i,x))})&&n.preventDefault()}}}})}}]),e}(R.default);D.keys={BACKSPACE:8,TAB:9,ENTER:13,ESCAPE:27,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46},D.DEFAULTS={bindings:{bold:d("bold"),italic:d("italic"),underline:d("underline"),indent:{key:D.keys.TAB,format:["blockquote","indent","list"],handler:function(t,e){if(e.collapsed&&0!==e.offset)return!0;this.quill.format("indent","+1",S.default.sources.USER)}},outdent:{key:D.keys.TAB,shiftKey:!0,format:["blockquote","indent","list"],handler:function(t,e){if(e.collapsed&&0!==e.offset)return!0;this.quill.format("indent","-1",S.default.sources.USER)}},"outdent backspace":{key:D.keys.BACKSPACE,collapsed:!0,shiftKey:null,metaKey:null,ctrlKey:null,altKey:null,format:["indent","list"],offset:0,handler:function(t,e){null!=e.format.indent?this.quill.format("indent","-1",S.default.sources.USER):null!=e.format.list&&this.quill.format("list",!1,S.default.sources.USER)}},"indent code-block":p(!0),"outdent code-block":p(!1),"remove tab":{key:D.keys.TAB,shiftKey:!0,collapsed:!0,prefix:/\t$/,handler:function(t){this.quill.deleteText(t.index-1,1,S.default.sources.USER)}},tab:{key:D.keys.TAB,handler:function(t){this.quill.history.cutoff();var e=(new N.default).retain(t.index).delete(t.length).insert("\t");this.quill.updateContents(e,S.default.sources.USER),this.quill.history.cutoff(),this.quill.setSelection(t.index+1,S.default.sources.SILENT)}},"list empty enter":{key:D.keys.ENTER,collapsed:!0,format:["list"],empty:!0,handler:function(t,e){this.quill.format("list",!1,S.default.sources.USER),e.format.indent&&this.quill.format("indent",!1,S.default.sources.USER)}},"checklist enter":{key:D.keys.ENTER,collapsed:!0,format:{list:"checked"},handler:function(t){var e=this.quill.getLine(t.index),n=b(e,2),r=n[0],o=n[1],i=(0,k.default)({},r.formats(),{list:"checked"}),l=(new N.default).retain(t.index).insert("\n",i).retain(r.length()-o-1).retain(1,{list:"unchecked"});this.quill.updateContents(l,S.default.sources.USER),this.quill.setSelection(t.index+1,S.default.sources.SILENT),this.quill.scrollIntoView()}},"header enter":{key:D.keys.ENTER,collapsed:!0,format:["header"],suffix:/^$/,handler:function(t,e){var n=this.quill.getLine(t.index),r=b(n,2),o=r[0],i=r[1],l=(new N.default).retain(t.index).insert("\n",e.format).retain(o.length()-i-1).retain(1,{header:null});this.quill.updateContents(l,S.default.sources.USER),this.quill.setSelection(t.index+1,S.default.sources.SILENT),this.quill.scrollIntoView()}},"list autofill":{key:" ",collapsed:!0,format:{list:!1},prefix:/^\s*?(\d+\.|-|\*|\[ ?\]|\[x\])$/,handler:function(t,e){var n=e.prefix.length,r=this.quill.getLine(t.index),o=b(r,2),i=o[0],l=o[1];if(l>n)return!0;var a=void 0;switch(e.prefix.trim()){case"[]":case"[ ]":a="unchecked";break;case"[x]":a="checked";break;case"-":case"*":a="bullet";break;default:a="ordered"}this.quill.insertText(t.index," ",S.default.sources.USER),this.quill.history.cutoff();var s=(new N.default).retain(t.index-l).delete(n+1).retain(i.length()-2-l).retain(1,{list:a});this.quill.updateContents(s,S.default.sources.USER),this.quill.history.cutoff(),this.quill.setSelection(t.index-n,S.default.sources.SILENT)}},"code exit":{key:D.keys.ENTER,collapsed:!0,format:["code-block"],prefix:/\n\n$/,suffix:/^\s+$/,handler:function(t){var e=this.quill.getLine(t.index),n=b(e,2),r=n[0],o=n[1],i=(new N.default).retain(t.index+r.length()-o-2).retain(1,{"code-block":null}).delete(1);this.quill.updateContents(i,S.default.sources.USER)}},"embed left":s(D.keys.LEFT,!1),"embed left shift":s(D.keys.LEFT,!0),"embed right":s(D.keys.RIGHT,!1),"embed right shift":s(D.keys.RIGHT,!0)}},e.default=D,e.SHORTKEY=B},function(t,e,n){"use strict";t.exports={align:{"":n(75),center:n(76),right:n(77),justify:n(78)},background:n(79),blockquote:n(80),bold:n(81),clean:n(82),code:n(40),"code-block":n(40),color:n(83),direction:{"":n(84),rtl:n(85)},float:{center:n(86),full:n(87),left:n(88),right:n(89)},formula:n(90),header:{1:n(91),2:n(92)},italic:n(93),image:n(94),indent:{"+1":n(95),"-1":n(96)},link:n(97),list:{ordered:n(98),bullet:n(99),check:n(100)},script:{sub:n(101),super:n(102)},strike:n(103),underline:n(104),video:n(105)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(1),o=function(){function t(t){this.domNode=t,this.domNode[r.DATA_KEY]={blot:this}}return Object.defineProperty(t.prototype,"statics",{get:function(){return this.constructor},enumerable:!0,configurable:!0}),t.create=function(t){if(null==this.tagName)throw new r.ParchmentError("Blot definition missing tagName");var e;return Array.isArray(this.tagName)?("string"==typeof t&&(t=t.toUpperCase(),parseInt(t).toString()===t&&(t=parseInt(t))),e="number"==typeof t?document.createElement(this.tagName[t-1]):this.tagName.indexOf(t)>-1?document.createElement(t):document.createElement(this.tagName[0])):e=document.createElement(this.tagName),this.className&&e.classList.add(this.className),e},t.prototype.attach=function(){null!=this.parent&&(this.scroll=this.parent.scroll)},t.prototype.clone=function(){var t=this.domNode.cloneNode(!1);return r.create(t)},t.prototype.detach=function(){null!=this.parent&&this.parent.removeChild(this),delete this.domNode[r.DATA_KEY]},t.prototype.deleteAt=function(t,e){this.isolate(t,e).remove()},t.prototype.formatAt=function(t,e,n,o){var i=this.isolate(t,e);if(null!=r.query(n,r.Scope.BLOT)&&o)i.wrap(n,o);else if(null!=r.query(n,r.Scope.ATTRIBUTE)){var l=r.create(this.statics.scope);i.wrap(l),l.format(n,o)}},t.prototype.insertAt=function(t,e,n){var o=null==n?r.create("text",e):r.create(e,n),i=this.split(t);this.parent.insertBefore(o,i)},t.prototype.insertInto=function(t,e){void 0===e&&(e=null),null!=this.parent&&this.parent.children.remove(this);var n=null;t.children.insertBefore(this,e),null!=e&&(n=e.domNode),this.domNode.parentNode==t.domNode&&this.domNode.nextSibling==n||t.domNode.insertBefore(this.domNode,n),this.parent=t,this.attach()},t.prototype.isolate=function(t,e){var n=this.split(t);return n.split(e),n},t.prototype.length=function(){return 1},t.prototype.offset=function(t){return void 0===t&&(t=this.parent),null==this.parent||this==t?0:this.parent.children.offset(this)+this.parent.offset(t)},t.prototype.optimize=function(t){null!=this.domNode[r.DATA_KEY]&&delete this.domNode[r.DATA_KEY].mutations},t.prototype.remove=function(){null!=this.domNode.parentNode&&this.domNode.parentNode.removeChild(this.domNode),this.detach()},t.prototype.replace=function(t){null!=t.parent&&(t.parent.insertBefore(this,t.next),t.remove())},t.prototype.replaceWith=function(t,e){var n="string"==typeof t?r.create(t,e):t;return n.replace(this),n},t.prototype.split=function(t,e){return 0===t?this:this.next},t.prototype.update=function(t,e){},t.prototype.wrap=function(t,e){var n="string"==typeof t?r.create(t,e):t;return null!=this.parent&&this.parent.insertBefore(n,this.next),n.appendChild(this),n},t.blotName="abstract",t}();e.default=o},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(11),o=n(29),i=n(30),l=n(1),a=function(){function t(t){this.attributes={},this.domNode=t,this.build()}return t.prototype.attribute=function(t,e){e?t.add(this.domNode,e)&&(null!=t.value(this.domNode)?this.attributes[t.attrName]=t:delete this.attributes[t.attrName]):(t.remove(this.domNode),delete this.attributes[t.attrName])},t.prototype.build=function(){var t=this;this.attributes={};var e=r.default.keys(this.domNode),n=o.default.keys(this.domNode),a=i.default.keys(this.domNode);e.concat(n).concat(a).forEach(function(e){var n=l.query(e,l.Scope.ATTRIBUTE);n instanceof r.default&&(t.attributes[n.attrName]=n)})},t.prototype.copy=function(t){var e=this;Object.keys(this.attributes).forEach(function(n){var r=e.attributes[n].value(e.domNode);t.format(n,r)})},t.prototype.move=function(t){var e=this;this.copy(t),Object.keys(this.attributes).forEach(function(t){e.attributes[t].remove(e.domNode)}),this.attributes={}},t.prototype.values=function(){var t=this;return Object.keys(this.attributes).reduce(function(e,n){return e[n]=t.attributes[n].value(t.domNode),e},{})},t}();e.default=a},function(t,e,n){"use strict";function r(t,e){return(t.getAttribute("class")||"").split(/\s+/).filter(function(t){return 0===t.indexOf(e+"-")})}var o=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var i=n(11),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.keys=function(t){return(t.getAttribute("class")||"").split(/\s+/).map(function(t){return t.split("-").slice(0,-1).join("-")})},e.prototype.add=function(t,e){return!!this.canAdd(t,e)&&(this.remove(t),t.classList.add(this.keyName+"-"+e),!0)},e.prototype.remove=function(t){r(t,this.keyName).forEach(function(e){t.classList.remove(e)}),0===t.classList.length&&t.removeAttribute("class")},e.prototype.value=function(t){var e=r(t,this.keyName)[0]||"",n=e.slice(this.keyName.length+1);return this.canAdd(t,n)?n:""},e}(i.default);e.default=l},function(t,e,n){"use strict";function r(t){var e=t.split("-"),n=e.slice(1).map(function(t){return t[0].toUpperCase()+t.slice(1)}).join("");return e[0]+n}var o=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var i=n(11),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.keys=function(t){return(t.getAttribute("style")||"").split(";").map(function(t){return t.split(":")[0].trim()})},e.prototype.add=function(t,e){return!!this.canAdd(t,e)&&(t.style[r(this.keyName)]=e,!0)},e.prototype.remove=function(t){t.style[r(this.keyName)]="",t.getAttribute("style")||t.removeAttribute("style")},e.prototype.value=function(t){var e=t.style[r(this.keyName)];return this.canAdd(t,e)?e:""},e}(i.default);e.default=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),s=function t(e,n,r){null===e&&(e=Function.prototype);var o=Object.getOwnPropertyDescriptor(e,n);if(void 0===o){var i=Object.getPrototypeOf(e);return null===i?void 0:t(i,n,r)}if("value"in o)return o.value;var l=o.get;if(void 0!==l)return l.call(r)},u=function(){function t(t,e){for(var n=0;n '},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;nr.right&&(i=r.right-o.right,this.root.style.left=e+i+"px"),o.leftr.bottom){var l=o.bottom-o.top,a=t.bottom-t.top+l;this.root.style.top=n-a+"px",this.root.classList.add("ql-flip")}return i}},{key:"show",value:function(){this.root.classList.remove("ql-editing"),this.root.classList.remove("ql-hidden")}}]),t}();e.default=i},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t){var e=t.match(/^(?:(https?):\/\/)?(?:(?:www|m)\.)?youtube\.com\/watch.*v=([a-zA-Z0-9_-]+)/)||t.match(/^(?:(https?):\/\/)?(?:(?:www|m)\.)?youtu\.be\/([a-zA-Z0-9_-]+)/);return e?(e[1]||"https")+"://www.youtube.com/embed/"+e[2]+"?showinfo=0":(e=t.match(/^(?:(https?):\/\/)?(?:www\.)?vimeo\.com\/(\d+)/))?(e[1]||"https")+"://player.vimeo.com/video/"+e[2]+"/":t}function s(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];e.forEach(function(e){var r=document.createElement("option");e===n?r.setAttribute("selected","selected"):r.setAttribute("value",e),t.appendChild(r)})}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.BaseTooltip=void 0;var u=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"link",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;this.root.classList.remove("ql-hidden"),this.root.classList.add("ql-editing"),null!=e?this.textbox.value=e:t!==this.root.getAttribute("data-mode")&&(this.textbox.value=""),this.position(this.quill.getBounds(this.quill.selection.savedRange)),this.textbox.select(),this.textbox.setAttribute("placeholder",this.textbox.getAttribute("data-"+t)||""),this.root.setAttribute("data-mode",t)}},{key:"restoreFocus",value:function(){var t=this.quill.scrollingContainer.scrollTop;this.quill.focus(),this.quill.scrollingContainer.scrollTop=t}},{key:"save",value:function(){var t=this.textbox.value;switch(this.root.getAttribute("data-mode")){case"link":var e=this.quill.root.scrollTop;this.linkRange?(this.quill.formatText(this.linkRange,"link",t,v.default.sources.USER),delete this.linkRange):(this.restoreFocus(),this.quill.format("link",t,v.default.sources.USER)),this.quill.root.scrollTop=e;break;case"video":t=a(t);case"formula":if(!t)break;var n=this.quill.getSelection(!0);if(null!=n){var r=n.index+n.length;this.quill.insertEmbed(r,this.root.getAttribute("data-mode"),t,v.default.sources.USER),"formula"===this.root.getAttribute("data-mode")&&this.quill.insertText(r+1," ",v.default.sources.USER),this.quill.setSelection(r+2,v.default.sources.USER)}}this.textbox.value="",this.hide()}}]),e}(A.default);e.BaseTooltip=M,e.default=L},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(46),i=r(o),l=n(34),a=n(36),s=n(62),u=n(63),c=r(u),f=n(64),h=r(f),p=n(65),d=r(p),y=n(35),v=n(24),b=n(37),g=n(38),m=n(39),_=r(m),O=n(66),w=r(O),x=n(15),k=r(x),E=n(67),N=r(E),j=n(68),A=r(j),q=n(69),T=r(q),P=n(70),S=r(P),C=n(71),L=r(C),M=n(13),R=r(M),I=n(72),B=r(I),D=n(73),U=r(D),F=n(74),H=r(F),K=n(26),z=r(K),Z=n(16),V=r(Z),W=n(41),G=r(W),Y=n(42),X=r(Y),$=n(43),Q=r($),J=n(107),tt=r(J),et=n(108),nt=r(et);i.default.register({"attributors/attribute/direction":a.DirectionAttribute,"attributors/class/align":l.AlignClass,"attributors/class/background":y.BackgroundClass,"attributors/class/color":v.ColorClass,"attributors/class/direction":a.DirectionClass,"attributors/class/font":b.FontClass,"attributors/class/size":g.SizeClass,"attributors/style/align":l.AlignStyle,"attributors/style/background":y.BackgroundStyle,"attributors/style/color":v.ColorStyle,"attributors/style/direction":a.DirectionStyle,"attributors/style/font":b.FontStyle,"attributors/style/size":g.SizeStyle},!0),i.default.register({"formats/align":l.AlignClass,"formats/direction":a.DirectionClass,"formats/indent":s.IndentClass,"formats/background":y.BackgroundStyle,"formats/color":v.ColorStyle,"formats/font":b.FontClass,"formats/size":g.SizeClass,"formats/blockquote":c.default,"formats/code-block":R.default,"formats/header":h.default,"formats/list":d.default,"formats/bold":_.default,"formats/code":M.Code,"formats/italic":w.default,"formats/link":k.default,"formats/script":N.default,"formats/strike":A.default,"formats/underline":T.default,"formats/image":S.default,"formats/video":L.default,"formats/list/item":p.ListItem,"modules/formula":B.default,"modules/syntax":U.default,"modules/toolbar":H.default,"themes/bubble":tt.default,"themes/snow":nt.default,"ui/icons":z.default,"ui/picker":V.default,"ui/icon-picker":X.default,"ui/color-picker":G.default,"ui/tooltip":Q.default},!0),e.default=i.default},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(0),i=r(o),l=n(6),a=r(l),s=n(3),u=r(s),c=n(14),f=r(c),h=n(23),p=r(h),d=n(31),y=r(d),v=n(33),b=r(v),g=n(5),m=r(g),_=n(59),O=r(_),w=n(8),x=r(w),k=n(60),E=r(k),N=n(61),j=r(N),A=n(25),q=r(A);a.default.register({"blots/block":u.default,"blots/block/embed":s.BlockEmbed,"blots/break":f.default,"blots/container":p.default,"blots/cursor":y.default,"blots/embed":b.default,"blots/inline":m.default,"blots/scroll":O.default,"blots/text":x.default,"modules/clipboard":E.default,"modules/history":j.default,"modules/keyboard":q.default}),i.default.register(u.default,f.default,y.default,m.default,O.default,x.default),e.default=a.default},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=function(){function t(){this.head=this.tail=null,this.length=0}return t.prototype.append=function(){for(var t=[],e=0;e1&&this.append.apply(this,t.slice(1))},t.prototype.contains=function(t){for(var e,n=this.iterator();e=n();)if(e===t)return!0;return!1},t.prototype.insertBefore=function(t,e){t&&(t.next=e,null!=e?(t.prev=e.prev,null!=e.prev&&(e.prev.next=t),e.prev=t,e===this.head&&(this.head=t)):null!=this.tail?(this.tail.next=t,t.prev=this.tail,this.tail=t):(t.prev=null,this.head=this.tail=t),this.length+=1)},t.prototype.offset=function(t){for(var e=0,n=this.head;null!=n;){if(n===t)return e;e+=n.length(),n=n.next}return-1},t.prototype.remove=function(t){this.contains(t)&&(null!=t.prev&&(t.prev.next=t.next),null!=t.next&&(t.next.prev=t.prev),t===this.head&&(this.head=t.next),t===this.tail&&(this.tail=t.prev),this.length-=1)},t.prototype.iterator=function(t){return void 0===t&&(t=this.head),function(){var e=t;return null!=t&&(t=t.next),e}},t.prototype.find=function(t,e){void 0===e&&(e=!1);for(var n,r=this.iterator();n=r();){var o=n.length();if(ta?n(r,t-a,Math.min(e,a+u-t)):n(r,0,Math.min(u,t+e-a)),a+=u}},t.prototype.map=function(t){return this.reduce(function(e,n){return e.push(t(n)),e},[])},t.prototype.reduce=function(t,e){for(var n,r=this.iterator();n=r();)e=t(e,n);return e},t}();e.default=r},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(17),i=n(1),l={attributes:!0,characterData:!0,characterDataOldValue:!0,childList:!0,subtree:!0},a=function(t){function e(e){var n=t.call(this,e)||this;return n.scroll=n,n.observer=new MutationObserver(function(t){n.update(t)}),n.observer.observe(n.domNode,l),n.attach(),n}return r(e,t),e.prototype.detach=function(){t.prototype.detach.call(this),this.observer.disconnect()},e.prototype.deleteAt=function(e,n){this.update(),0===e&&n===this.length()?this.children.forEach(function(t){t.remove()}):t.prototype.deleteAt.call(this,e,n)},e.prototype.formatAt=function(e,n,r,o){this.update(),t.prototype.formatAt.call(this,e,n,r,o)},e.prototype.insertAt=function(e,n,r){this.update(),t.prototype.insertAt.call(this,e,n,r)},e.prototype.optimize=function(e,n){var r=this;void 0===e&&(e=[]),void 0===n&&(n={}),t.prototype.optimize.call(this,n);for(var l=[].slice.call(this.observer.takeRecords());l.length>0;)e.push(l.pop());for(var a=function(t,e){void 0===e&&(e=!0),null!=t&&t!==r&&null!=t.domNode.parentNode&&(null==t.domNode[i.DATA_KEY].mutations&&(t.domNode[i.DATA_KEY].mutations=[]),e&&a(t.parent))},s=function(t){null!=t.domNode[i.DATA_KEY]&&null!=t.domNode[i.DATA_KEY].mutations&&(t instanceof o.default&&t.children.forEach(s),t.optimize(n))},u=e,c=0;u.length>0;c+=1){if(c>=100)throw new Error("[Parchment] Maximum optimize iterations reached");for(u.forEach(function(t){var e=i.find(t.target,!0);null!=e&&(e.domNode===t.target&&("childList"===t.type?(a(i.find(t.previousSibling,!1)),[].forEach.call(t.addedNodes,function(t){var e=i.find(t,!1);a(e,!1),e instanceof o.default&&e.children.forEach(function(t){a(t,!1)})})):"attributes"===t.type&&a(e.prev)),a(e))}),this.children.forEach(s),u=[].slice.call(this.observer.takeRecords()),l=u.slice();l.length>0;)e.push(l.pop())}},e.prototype.update=function(e,n){var r=this;void 0===n&&(n={}),e=e||this.observer.takeRecords(),e.map(function(t){var e=i.find(t.target,!0);return null==e?null:null==e.domNode[i.DATA_KEY].mutations?(e.domNode[i.DATA_KEY].mutations=[t],e):(e.domNode[i.DATA_KEY].mutations.push(t),null)}).forEach(function(t){null!=t&&t!==r&&null!=t.domNode[i.DATA_KEY]&&t.update(t.domNode[i.DATA_KEY].mutations||[],n)}),null!=this.domNode[i.DATA_KEY].mutations&&t.prototype.update.call(this,this.domNode[i.DATA_KEY].mutations,n),this.optimize(e,n)},e.blotName="scroll",e.defaultChild="block",e.scope=i.Scope.BLOCK_BLOT,e.tagName="DIV",e}(o.default);e.default=a},function(t,e,n){"use strict";function r(t,e){if(Object.keys(t).length!==Object.keys(e).length)return!1;for(var n in t)if(t[n]!==e[n])return!1;return!0}var o=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var i=n(18),l=n(1),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.formats=function(n){if(n.tagName!==e.tagName)return t.formats.call(this,n)},e.prototype.format=function(n,r){var o=this;n!==this.statics.blotName||r?t.prototype.format.call(this,n,r):(this.children.forEach(function(t){t instanceof i.default||(t=t.wrap(e.blotName,!0)),o.attributes.copy(t)}),this.unwrap())},e.prototype.formatAt=function(e,n,r,o){if(null!=this.formats()[r]||l.query(r,l.Scope.ATTRIBUTE)){this.isolate(e,n).format(r,o)}else t.prototype.formatAt.call(this,e,n,r,o)},e.prototype.optimize=function(n){t.prototype.optimize.call(this,n);var o=this.formats();if(0===Object.keys(o).length)return this.unwrap();var i=this.next;i instanceof e&&i.prev===this&&r(o,i.formats())&&(i.moveChildren(this),i.remove())},e.blotName="inline",e.scope=l.Scope.INLINE_BLOT,e.tagName="SPAN",e}(i.default);e.default=a},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(18),i=n(1),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return r(e,t),e.formats=function(n){var r=i.query(e.blotName).tagName;if(n.tagName!==r)return t.formats.call(this,n)},e.prototype.format=function(n,r){null!=i.query(n,i.Scope.BLOCK)&&(n!==this.statics.blotName||r?t.prototype.format.call(this,n,r):this.replaceWith(e.blotName))},e.prototype.formatAt=function(e,n,r,o){null!=i.query(r,i.Scope.BLOCK)?this.format(r,o):t.prototype.formatAt.call(this,e,n,r,o)},e.prototype.insertAt=function(e,n,r){if(null==r||null!=i.query(n,i.Scope.INLINE))t.prototype.insertAt.call(this,e,n,r);else{var o=this.split(e),l=i.create(n,r);o.parent.insertBefore(l,o)}},e.prototype.update=function(e,n){navigator.userAgent.match(/Trident/)?this.build():t.prototype.update.call(this,e,n)},e.blotName="block",e.scope=i.Scope.BLOCK_BLOT,e.tagName="P",e}(o.default);e.default=l},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(19),i=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return r(e,t),e.formats=function(t){},e.prototype.format=function(e,n){t.prototype.formatAt.call(this,0,this.length(),e,n)},e.prototype.formatAt=function(e,n,r,o){0===e&&n===this.length()?this.format(r,o):t.prototype.formatAt.call(this,e,n,r,o)},e.prototype.formats=function(){return this.statics.formats(this.domNode)},e}(o.default);e.default=i},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(19),i=n(1),l=function(t){function e(e){var n=t.call(this,e)||this;return n.text=n.statics.value(n.domNode),n}return r(e,t),e.create=function(t){return document.createTextNode(t)},e.value=function(t){var e=t.data;return e.normalize&&(e=e.normalize()),e},e.prototype.deleteAt=function(t,e){this.domNode.data=this.text=this.text.slice(0,t)+this.text.slice(t+e)},e.prototype.index=function(t,e){return this.domNode===t?e:-1},e.prototype.insertAt=function(e,n,r){null==r?(this.text=this.text.slice(0,e)+n+this.text.slice(e),this.domNode.data=this.text):t.prototype.insertAt.call(this,e,n,r)},e.prototype.length=function(){return this.text.length},e.prototype.optimize=function(n){t.prototype.optimize.call(this,n),this.text=this.statics.value(this.domNode),0===this.text.length?this.remove():this.next instanceof e&&this.next.prev===this&&(this.insertAt(this.length(),this.next.value()),this.next.remove())},e.prototype.position=function(t,e){return void 0===e&&(e=!1),[this.domNode,t]},e.prototype.split=function(t,e){if(void 0===e&&(e=!1),!e){if(0===t)return this;if(t===this.length())return this.next}var n=i.create(this.domNode.splitText(t));return this.parent.insertBefore(n,this.next),this.text=this.statics.value(this.domNode),n},e.prototype.update=function(t,e){var n=this;t.some(function(t){return"characterData"===t.type&&t.target===n.domNode})&&(this.text=this.statics.value(this.domNode))},e.prototype.value=function(){return this.text},e.blotName="text",e.scope=i.Scope.INLINE_BLOT,e}(o.default);e.default=l},function(t,e,n){"use strict";var r=document.createElement("div");if(r.classList.toggle("test-class",!1),r.classList.contains("test-class")){var o=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(t,e){return arguments.length>1&&!this.contains(t)==!e?e:o.call(this,t)}}String.prototype.startsWith||(String.prototype.startsWith=function(t,e){return e=e||0,this.substr(e,t.length)===t}),String.prototype.endsWith||(String.prototype.endsWith=function(t,e){var n=this.toString();("number"!=typeof e||!isFinite(e)||Math.floor(e)!==e||e>n.length)&&(e=n.length),e-=t.length;var r=n.indexOf(t,e);return-1!==r&&r===e}),Array.prototype.find||Object.defineProperty(Array.prototype,"find",{value:function(t){if(null===this)throw new TypeError("Array.prototype.find called on null or undefined");if("function"!=typeof t)throw new TypeError("predicate must be a function");for(var e,n=Object(this),r=n.length>>>0,o=arguments[1],i=0;ie.length?t:e,l=t.length>e.length?e:t,a=i.indexOf(l);if(-1!=a)return r=[[y,i.substring(0,a)],[v,l],[y,i.substring(a+l.length)]],t.length>e.length&&(r[0][0]=r[2][0]=d),r;if(1==l.length)return[[d,t],[y,e]];var u=s(t,e);if(u){var c=u[0],f=u[1],h=u[2],p=u[3],b=u[4],g=n(c,h),m=n(f,p);return g.concat([[v,b]],m)}return o(t,e)}function o(t,e){for(var n=t.length,r=e.length,o=Math.ceil((n+r)/2),l=o,a=2*o,s=new Array(a),u=new Array(a),c=0;cn)v+=2;else if(x>r)p+=2;else if(h){var k=l+f-_;if(k>=0&&k=E)return i(t,e,O,x)}}}for(var N=-m+b;N<=m-g;N+=2){var E,k=l+N;E=N==-m||N!=m&&u[k-1]n)g+=2;else if(j>r)b+=2;else if(!h){var w=l+f-N;if(w>=0&&w=E)return i(t,e,O,x)}}}}return[[d,t],[y,e]]}function i(t,e,r,o){var i=t.substring(0,r),l=e.substring(0,o),a=t.substring(r),s=e.substring(o),u=n(i,l),c=n(a,s);return u.concat(c)}function l(t,e){if(!t||!e||t.charAt(0)!=e.charAt(0))return 0;for(var n=0,r=Math.min(t.length,e.length),o=r,i=0;n=t.length?[r,o,i,s,f]:null}var r=t.length>e.length?t:e,o=t.length>e.length?e:t;if(r.length<4||2*o.lengthu[4].length?s:u:s;var c,f,h,p;return t.length>e.length?(c=i[0],f=i[1],h=i[2],p=i[3]):(h=i[0],p=i[1],c=i[2],f=i[3]),[c,f,h,p,i[4]]}function u(t){t.push([v,""]);for(var e,n=0,r=0,o=0,i="",s="";n1?(0!==r&&0!==o&&(e=l(s,i),0!==e&&(n-r-o>0&&t[n-r-o-1][0]==v?t[n-r-o-1][1]+=s.substring(0,e):(t.splice(0,0,[v,s.substring(0,e)]),n++),s=s.substring(e),i=i.substring(e)),0!==(e=a(s,i))&&(t[n][1]=s.substring(s.length-e)+t[n][1],s=s.substring(0,s.length-e),i=i.substring(0,i.length-e))),0===r?t.splice(n-o,r+o,[y,s]):0===o?t.splice(n-r,r+o,[d,i]):t.splice(n-r-o,r+o,[d,i],[y,s]),n=n-r-o+(r?1:0)+(o?1:0)+1):0!==n&&t[n-1][0]==v?(t[n-1][1]+=t[n][1],t.splice(n,1)):n++,o=0,r=0,i="",s=""}""===t[t.length-1][1]&&t.pop();var c=!1;for(n=1;n0&&r.splice(o+2,0,[l[0],a]),p(r,o,3)}return t}function h(t){for(var e=!1,n=function(t){return t.charCodeAt(0)>=56320&&t.charCodeAt(0)<=57343},r=2;r=55296&&t.charCodeAt(t.length-1)<=56319}(t[r-2][1])&&t[r-1][0]===d&&n(t[r-1][1])&&t[r][0]===y&&n(t[r][1])&&(e=!0,t[r-1][1]=t[r-2][1].slice(-1)+t[r-1][1],t[r][1]=t[r-2][1].slice(-1)+t[r][1],t[r-2][1]=t[r-2][1].slice(0,-1));if(!e)return t;for(var o=[],r=0;r0&&o.push(t[r]);return o}function p(t,e,n){for(var r=e+n-1;r>=0&&r>=e-1;r--)if(r+1=r&&!a.endsWith("\n")&&(n=!0),e.scroll.insertAt(t,a);var c=e.scroll.line(t),f=u(c,2),h=f[0],p=f[1],y=(0,T.default)({},(0,O.bubbleFormats)(h));if(h instanceof w.default){var b=h.descendant(v.default.Leaf,p),g=u(b,1),m=g[0];y=(0,T.default)(y,(0,O.bubbleFormats)(m))}l=d.default.attributes.diff(y,l)||{}}else if("object"===s(o.insert)){var _=Object.keys(o.insert)[0];if(null==_)return t;e.scroll.insertAt(t,_,o.insert[_])}r+=i}return Object.keys(l).forEach(function(n){e.scroll.formatAt(t,i,n,l[n])}),t+i},0),t.reduce(function(t,n){return"number"==typeof n.delete?(e.scroll.deleteAt(t,n.delete),t):t+(n.retain||n.insert.length||1)},0),this.scroll.batchEnd(),this.update(t)}},{key:"deleteText",value:function(t,e){return this.scroll.deleteAt(t,e),this.update((new h.default).retain(t).delete(e))}},{key:"formatLine",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return this.scroll.update(),Object.keys(r).forEach(function(o){if(null==n.scroll.whitelist||n.scroll.whitelist[o]){var i=n.scroll.lines(t,Math.max(e,1)),l=e;i.forEach(function(e){var i=e.length();if(e instanceof g.default){var a=t-e.offset(n.scroll),s=e.newlineIndex(a+l)-a+1;e.formatAt(a,s,o,r[o])}else e.format(o,r[o]);l-=i})}}),this.scroll.optimize(),this.update((new h.default).retain(t).retain(e,(0,N.default)(r)))}},{key:"formatText",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return Object.keys(r).forEach(function(o){n.scroll.formatAt(t,e,o,r[o])}),this.update((new h.default).retain(t).retain(e,(0,N.default)(r)))}},{key:"getContents",value:function(t,e){return this.delta.slice(t,t+e)}},{key:"getDelta",value:function(){return this.scroll.lines().reduce(function(t,e){return t.concat(e.delta())},new h.default)}},{key:"getFormat",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=[],r=[];0===e?this.scroll.path(t).forEach(function(t){var e=u(t,1),o=e[0];o instanceof w.default?n.push(o):o instanceof v.default.Leaf&&r.push(o)}):(n=this.scroll.lines(t,e),r=this.scroll.descendants(v.default.Leaf,t,e));var o=[n,r].map(function(t){if(0===t.length)return{};for(var e=(0,O.bubbleFormats)(t.shift());Object.keys(e).length>0;){var n=t.shift();if(null==n)return e;e=l((0,O.bubbleFormats)(n),e)}return e});return T.default.apply(T.default,o)}},{key:"getText",value:function(t,e){return this.getContents(t,e).filter(function(t){return"string"==typeof t.insert}).map(function(t){return t.insert}).join("")}},{key:"insertEmbed",value:function(t,e,n){return this.scroll.insertAt(t,e,n),this.update((new h.default).retain(t).insert(o({},e,n)))}},{key:"insertText",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return e=e.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),this.scroll.insertAt(t,e),Object.keys(r).forEach(function(o){n.scroll.formatAt(t,e.length,o,r[o])}),this.update((new h.default).retain(t).insert(e,(0,N.default)(r)))}},{key:"isBlank",value:function(){if(0==this.scroll.children.length)return!0;if(this.scroll.children.length>1)return!1;var t=this.scroll.children.head;return t.statics.blotName===w.default.blotName&&(!(t.children.length>1)&&t.children.head instanceof k.default)}},{key:"removeFormat",value:function(t,e){var n=this.getText(t,e),r=this.scroll.line(t+e),o=u(r,2),i=o[0],l=o[1],a=0,s=new h.default;null!=i&&(a=i instanceof g.default?i.newlineIndex(l)-l+1:i.length()-l,s=i.delta().slice(l,l+a-1).insert("\n"));var c=this.getContents(t,e+a),f=c.diff((new h.default).insert(n).concat(s)),p=(new h.default).retain(t).concat(f);return this.applyDelta(p)}},{key:"update",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,r=this.delta;if(1===e.length&&"characterData"===e[0].type&&e[0].target.data.match(P)&&v.default.find(e[0].target)){var o=v.default.find(e[0].target),i=(0,O.bubbleFormats)(o),l=o.offset(this.scroll),a=e[0].oldValue.replace(_.default.CONTENTS,""),s=(new h.default).insert(a),u=(new h.default).insert(o.value());t=(new h.default).retain(l).concat(s.diff(u,n)).reduce(function(t,e){return e.insert?t.insert(e.insert,i):t.push(e)},new h.default),this.delta=r.compose(t)}else this.delta=this.getDelta(),t&&(0,A.default)(r.compose(t),this.delta)||(t=r.diff(this.delta,n));return t}}]),t}();e.default=S},function(t,e){"use strict";function n(){}function r(t,e,n){this.fn=t,this.context=e,this.once=n||!1}function o(){this._events=new n,this._eventsCount=0}var i=Object.prototype.hasOwnProperty,l="~";Object.create&&(n.prototype=Object.create(null),(new n).__proto__||(l=!1)),o.prototype.eventNames=function(){var t,e,n=[];if(0===this._eventsCount)return n;for(e in t=this._events)i.call(t,e)&&n.push(l?e.slice(1):e);return Object.getOwnPropertySymbols?n.concat(Object.getOwnPropertySymbols(t)):n},o.prototype.listeners=function(t,e){var n=l?l+t:t,r=this._events[n];if(e)return!!r;if(!r)return[];if(r.fn)return[r.fn];for(var o=0,i=r.length,a=new Array(i);o0){if(i instanceof y.BlockEmbed||f instanceof y.BlockEmbed)return void this.optimize();if(i instanceof _.default){var h=i.newlineIndex(i.length(),!0);if(h>-1&&(i=i.split(h+1))===f)return void this.optimize()}else if(f instanceof _.default){var p=f.newlineIndex(0);p>-1&&f.split(p+1)}var d=f.children.head instanceof g.default?null:f.children.head;i.moveChildren(f,d),i.remove()}this.optimize()}},{key:"enable",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.domNode.setAttribute("contenteditable",t)}},{key:"formatAt",value:function(t,n,r,o){(null==this.whitelist||this.whitelist[r])&&(c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"formatAt",this).call(this,t,n,r,o),this.optimize())}},{key:"insertAt",value:function(t,n,r){if(null==r||null==this.whitelist||this.whitelist[n]){if(t>=this.length())if(null==r||null==h.default.query(n,h.default.Scope.BLOCK)){var o=h.default.create(this.statics.defaultChild);this.appendChild(o),null==r&&n.endsWith("\n")&&(n=n.slice(0,-1)),o.insertAt(0,n,r)}else{var i=h.default.create(n,r);this.appendChild(i)}else c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"insertAt",this).call(this,t,n,r);this.optimize()}}},{key:"insertBefore",value:function(t,n){if(t.statics.scope===h.default.Scope.INLINE_BLOT){var r=h.default.create(this.statics.defaultChild);r.appendChild(t),t=r}c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"insertBefore",this).call(this,t,n)}},{key:"leaf",value:function(t){return this.path(t).pop()||[null,-1]}},{key:"line",value:function(t){return t===this.length()?this.line(t-1):this.descendant(a,t)}},{key:"lines",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Number.MAX_VALUE;return function t(e,n,r){var o=[],i=r;return e.children.forEachAt(n,r,function(e,n,r){a(e)?o.push(e):e instanceof h.default.Container&&(o=o.concat(t(e,n,i))),i-=r}),o}(this,t,e)}},{key:"optimize",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};!0!==this.batch&&(c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"optimize",this).call(this,t,n),t.length>0&&this.emitter.emit(d.default.events.SCROLL_OPTIMIZE,t,n))}},{key:"path",value:function(t){return c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"path",this).call(this,t).slice(1)}},{key:"update",value:function(t){if(!0!==this.batch){var n=d.default.sources.USER;"string"==typeof t&&(n=t),Array.isArray(t)||(t=this.observer.takeRecords()),t.length>0&&this.emitter.emit(d.default.events.SCROLL_BEFORE_UPDATE,n,t),c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"update",this).call(this,t.concat([])),t.length>0&&this.emitter.emit(d.default.events.SCROLL_UPDATE,n,t)}}}]),e}(h.default.Scroll);x.blotName="scroll",x.className="ql-editor",x.tagName="DIV",x.defaultChild="block",x.allowedChildren=[v.default,y.BlockEmbed,w.default],e.default=x},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function l(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function a(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function s(t,e,n){return"object"===(void 0===e?"undefined":x(e))?Object.keys(e).reduce(function(t,n){return s(t,n,e[n])},t):t.reduce(function(t,r){return r.attributes&&r.attributes[e]?t.push(r):t.insert(r.insert,(0,j.default)({},o({},e,n),r.attributes))},new q.default)}function u(t){if(t.nodeType!==Node.ELEMENT_NODE)return{};return t["__ql-computed-style"]||(t["__ql-computed-style"]=window.getComputedStyle(t))}function c(t,e){for(var n="",r=t.ops.length-1;r>=0&&n.length-1}function h(t,e,n){return t.nodeType===t.TEXT_NODE?n.reduce(function(e,n){return n(t,e)},new q.default):t.nodeType===t.ELEMENT_NODE?[].reduce.call(t.childNodes||[],function(r,o){var i=h(o,e,n);return o.nodeType===t.ELEMENT_NODE&&(i=e.reduce(function(t,e){return e(o,t)},i),i=(o[W]||[]).reduce(function(t,e){return e(o,t)},i)),r.concat(i)},new q.default):new q.default}function p(t,e,n){return s(n,t,!0)}function d(t,e){var n=P.default.Attributor.Attribute.keys(t),r=P.default.Attributor.Class.keys(t),o=P.default.Attributor.Style.keys(t),i={};return n.concat(r).concat(o).forEach(function(e){var n=P.default.query(e,P.default.Scope.ATTRIBUTE);null!=n&&(i[n.attrName]=n.value(t),i[n.attrName])||(n=Y[e],null==n||n.attrName!==e&&n.keyName!==e||(i[n.attrName]=n.value(t)||void 0),null==(n=X[e])||n.attrName!==e&&n.keyName!==e||(n=X[e],i[n.attrName]=n.value(t)||void 0))}),Object.keys(i).length>0&&(e=s(e,i)),e}function y(t,e){var n=P.default.query(t);if(null==n)return e;if(n.prototype instanceof P.default.Embed){var r={},o=n.value(t);null!=o&&(r[n.blotName]=o,e=(new q.default).insert(r,n.formats(t)))}else"function"==typeof n.formats&&(e=s(e,n.blotName,n.formats(t)));return e}function v(t,e){return c(e,"\n")||e.insert("\n"),e}function b(){return new q.default}function g(t,e){var n=P.default.query(t);if(null==n||"list-item"!==n.blotName||!c(e,"\n"))return e;for(var r=-1,o=t.parentNode;!o.classList.contains("ql-clipboard");)"list"===(P.default.query(o)||{}).blotName&&(r+=1),o=o.parentNode;return r<=0?e:e.compose((new q.default).retain(e.length()-1).retain(1,{indent:r}))}function m(t,e){return c(e,"\n")||(f(t)||e.length()>0&&t.nextSibling&&f(t.nextSibling))&&e.insert("\n"),e}function _(t,e){if(f(t)&&null!=t.nextElementSibling&&!c(e,"\n\n")){var n=t.offsetHeight+parseFloat(u(t).marginTop)+parseFloat(u(t).marginBottom);t.nextElementSibling.offsetTop>t.offsetTop+1.5*n&&e.insert("\n")}return e}function O(t,e){var n={},r=t.style||{};return r.fontStyle&&"italic"===u(t).fontStyle&&(n.italic=!0),r.fontWeight&&(u(t).fontWeight.startsWith("bold")||parseInt(u(t).fontWeight)>=700)&&(n.bold=!0),Object.keys(n).length>0&&(e=s(e,n)),parseFloat(r.textIndent||0)>0&&(e=(new q.default).insert("\t").concat(e)),e}function w(t,e){var n=t.data;if("O:P"===t.parentNode.tagName)return e.insert(n.trim());if(0===n.trim().length&&t.parentNode.classList.contains("ql-clipboard"))return e;if(!u(t.parentNode).whiteSpace.startsWith("pre")){var r=function(t,e){return e=e.replace(/[^\u00a0]/g,""),e.length<1&&t?" ":e};n=n.replace(/\r\n/g," ").replace(/\n/g," "),n=n.replace(/\s\s+/g,r.bind(r,!0)),(null==t.previousSibling&&f(t.parentNode)||null!=t.previousSibling&&f(t.previousSibling))&&(n=n.replace(/^\s+/,r.bind(r,!1))),(null==t.nextSibling&&f(t.parentNode)||null!=t.nextSibling&&f(t.nextSibling))&&(n=n.replace(/\s+$/,r.bind(r,!1)))}return e.insert(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.matchText=e.matchSpacing=e.matchNewline=e.matchBlot=e.matchAttributor=e.default=void 0;var x="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},k=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),E=function(){function t(t,e){for(var n=0;n\r?\n +\<"),this.convert();var e=this.quill.getFormat(this.quill.selection.savedRange.index);if(e[F.default.blotName]){var n=this.container.innerText;return this.container.innerHTML="",(new q.default).insert(n,o({},F.default.blotName,e[F.default.blotName]))}var r=this.prepareMatching(),i=k(r,2),l=i[0],a=i[1],s=h(this.container,l,a);return c(s,"\n")&&null==s.ops[s.ops.length-1].attributes&&(s=s.compose((new q.default).retain(s.length()-1).delete(1))),V.log("convert",this.container.innerHTML,s),this.container.innerHTML="",s}},{key:"dangerouslyPasteHTML",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:C.default.sources.API;if("string"==typeof t)this.quill.setContents(this.convert(t),e),this.quill.setSelection(0,C.default.sources.SILENT);else{var r=this.convert(e);this.quill.updateContents((new q.default).retain(t).concat(r),n),this.quill.setSelection(t+r.length(),C.default.sources.SILENT)}}},{key:"onPaste",value:function(t){var e=this;if(!t.defaultPrevented&&this.quill.isEnabled()){var n=this.quill.getSelection(),r=(new q.default).retain(n.index),o=this.quill.scrollingContainer.scrollTop;this.container.focus(),this.quill.selection.update(C.default.sources.SILENT),setTimeout(function(){r=r.concat(e.convert()).delete(n.length),e.quill.updateContents(r,C.default.sources.USER),e.quill.setSelection(r.length()-n.length,C.default.sources.SILENT),e.quill.scrollingContainer.scrollTop=o,e.quill.focus()},1)}}},{key:"prepareMatching",value:function(){var t=this,e=[],n=[];return this.matchers.forEach(function(r){var o=k(r,2),i=o[0],l=o[1];switch(i){case Node.TEXT_NODE:n.push(l);break;case Node.ELEMENT_NODE:e.push(l);break;default:[].forEach.call(t.container.querySelectorAll(i),function(t){t[W]=t[W]||[],t[W].push(l)})}}),[e,n]}}]),e}(I.default);$.DEFAULTS={matchers:[],matchVisual:!0},e.default=$,e.matchAttributor=d,e.matchBlot=y,e.matchNewline=m,e.matchSpacing=_,e.matchText=w},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t){var e=t.ops[t.ops.length-1];return null!=e&&(null!=e.insert?"string"==typeof e.insert&&e.insert.endsWith("\n"):null!=e.attributes&&Object.keys(e.attributes).some(function(t){return null!=f.default.query(t,f.default.Scope.BLOCK)}))}function s(t){var e=t.reduce(function(t,e){return t+=e.delete||0},0),n=t.length()-e;return a(t)&&(n-=1),n}Object.defineProperty(e,"__esModule",{value:!0}),e.getLastChangeIndex=e.default=void 0;var u=function(){function t(t,e){for(var n=0;nr&&this.stack.undo.length>0){var o=this.stack.undo.pop();n=n.compose(o.undo),t=o.redo.compose(t)}else this.lastRecorded=r;this.stack.undo.push({redo:t,undo:n}),this.stack.undo.length>this.options.maxStack&&this.stack.undo.shift()}}},{key:"redo",value:function(){this.change("redo","undo")}},{key:"transform",value:function(t){this.stack.undo.forEach(function(e){e.undo=t.transform(e.undo,!0),e.redo=t.transform(e.redo,!0)}),this.stack.redo.forEach(function(e){e.undo=t.transform(e.undo,!0),e.redo=t.transform(e.redo,!0)})}},{key:"undo",value:function(){this.change("undo","redo")}}]),e}(y.default);v.DEFAULTS={delay:1e3,maxStack:100,userOnly:!1},e.default=v,e.getLastChangeIndex=s},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.IndentClass=void 0;var l=function(){function t(t,e){for(var n=0;n0&&this.children.tail.format(t,e)}},{key:"formats",value:function(){return o({},this.statics.blotName,this.statics.formats(this.domNode))}},{key:"insertBefore",value:function(t,n){if(t instanceof v)u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"insertBefore",this).call(this,t,n);else{var r=null==n?this.length():n.offset(this),o=this.split(r);o.parent.insertBefore(t,o)}}},{key:"optimize",value:function(t){u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"optimize",this).call(this,t);var n=this.next;null!=n&&n.prev===this&&n.statics.blotName===this.statics.blotName&&n.domNode.tagName===this.domNode.tagName&&n.domNode.getAttribute("data-checked")===this.domNode.getAttribute("data-checked")&&(n.moveChildren(this),n.remove())}},{key:"replace",value:function(t){if(t.statics.blotName!==this.statics.blotName){var n=f.default.create(this.statics.defaultChild);t.moveChildren(n),this.appendChild(n)}u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"replace",this).call(this,t)}}]),e}(y.default);b.blotName="list",b.scope=f.default.Scope.BLOCK_BLOT,b.tagName=["OL","UL"],b.defaultChild="list-item",b.allowedChildren=[v],e.ListItem=v,e.default=b},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=n(39),a=function(t){return t&&t.__esModule?t:{default:t}}(l),s=function(t){function e(){return r(this,e),o(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return i(e,t),e}(a.default);s.blotName="italic",s.tagName=["EM","I"],e.default=s},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;n-1?n?this.domNode.setAttribute(t,n):this.domNode.removeAttribute(t):a(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"format",this).call(this,t,n)}}],[{key:"create",value:function(t){var n=a(e.__proto__||Object.getPrototypeOf(e),"create",this).call(this,t);return"string"==typeof t&&n.setAttribute("src",this.sanitize(t)),n}},{key:"formats",value:function(t){return f.reduce(function(e,n){return t.hasAttribute(n)&&(e[n]=t.getAttribute(n)),e},{})}},{key:"match",value:function(t){return/\.(jpe?g|gif|png)$/.test(t)||/^data:image\/.+;base64/.test(t)}},{key:"sanitize",value:function(t){return(0,c.sanitize)(t,["http","https","data"])?t:"//:0"}},{key:"value",value:function(t){return t.getAttribute("src")}}]),e}(u.default.Embed);h.blotName="image",h.tagName="IMG",e.default=h},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;n-1?n?this.domNode.setAttribute(t,n):this.domNode.removeAttribute(t):a(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"format",this).call(this,t,n)}}],[{key:"create",value:function(t){var n=a(e.__proto__||Object.getPrototypeOf(e),"create",this).call(this,t);return n.setAttribute("frameborder","0"),n.setAttribute("allowfullscreen",!0),n.setAttribute("src",this.sanitize(t)),n}},{key:"formats",value:function(t){return f.reduce(function(e,n){return t.hasAttribute(n)&&(e[n]=t.getAttribute(n)),e},{})}},{key:"sanitize",value:function(t){return c.default.sanitize(t)}},{key:"value",value:function(t){return t.getAttribute("src")}}]),e}(s.BlockEmbed);h.blotName="video",h.className="ql-video",h.tagName="IFRAME",e.default=h},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.FormulaBlot=void 0;var a=function(){function t(t,e){for(var n=0;n0||null==this.cachedText)&&(this.domNode.innerHTML=t(e),this.domNode.normalize(),this.attach()),this.cachedText=e)}}]),e}(v.default);b.className="ql-syntax";var g=new c.default.Attributor.Class("token","hljs",{scope:c.default.Scope.INLINE}),m=function(t){function e(t,n){o(this,e);var r=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,n));if("function"!=typeof r.options.highlight)throw new Error("Syntax module requires highlight.js. Please include the library on the page before Quill.");var l=null;return r.quill.on(h.default.events.SCROLL_OPTIMIZE,function(){clearTimeout(l),l=setTimeout(function(){r.highlight(),l=null},r.options.interval)}),r.highlight(),r}return l(e,t),a(e,null,[{key:"register",value:function(){h.default.register(g,!0),h.default.register(b,!0)}}]),a(e,[{key:"highlight",value:function(){var t=this;if(!this.quill.selection.composing){this.quill.update(h.default.sources.USER);var e=this.quill.getSelection();this.quill.scroll.descendants(b).forEach(function(e){e.highlight(t.options.highlight)}),this.quill.update(h.default.sources.SILENT),null!=e&&this.quill.setSelection(e,h.default.sources.SILENT)}}}]),e}(d.default);m.DEFAULTS={highlight:function(){return null==window.hljs?null:function(t){return window.hljs.highlightAuto(t).value}}(),interval:1e3},e.CodeBlock=b,e.CodeToken=g,e.default=m},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function l(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function a(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function s(t,e,n){var r=document.createElement("button");r.setAttribute("type","button"),r.classList.add("ql-"+e),null!=n&&(r.value=n),t.appendChild(r)}function u(t,e){Array.isArray(e[0])||(e=[e]),e.forEach(function(e){var n=document.createElement("span");n.classList.add("ql-formats"),e.forEach(function(t){if("string"==typeof t)s(n,t);else{var e=Object.keys(t)[0],r=t[e];Array.isArray(r)?c(n,e,r):s(n,e,r)}}),t.appendChild(n)})}function c(t,e,n){var r=document.createElement("select");r.classList.add("ql-"+e),n.forEach(function(t){var e=document.createElement("option");!1!==t?e.setAttribute("value",t):e.setAttribute("selected","selected"),r.appendChild(e)}),t.appendChild(r)}Object.defineProperty(e,"__esModule",{value:!0}),e.addControls=e.default=void 0;var f=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),h=function(){function t(t,e){for(var n=0;n '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.BubbleTooltip=void 0;var a=function t(e,n,r){null===e&&(e=Function.prototype);var o=Object.getOwnPropertyDescriptor(e,n);if(void 0===o){var i=Object.getPrototypeOf(e);return null===i?void 0:t(i,n,r)}if("value"in o)return o.value;var l=o.get;if(void 0!==l)return l.call(r)},s=function(){function t(t,e){for(var n=0;n0&&o===h.default.sources.USER){r.show(),r.root.style.left="0px",r.root.style.width="",r.root.style.width=r.root.offsetWidth+"px";var i=r.quill.getLines(e.index,e.length);if(1===i.length)r.position(r.quill.getBounds(e));else{var l=i[i.length-1],a=r.quill.getIndex(l),s=Math.min(l.length()-1,e.index+e.length-a),u=r.quill.getBounds(new y.Range(a,s));r.position(u)}}else document.activeElement!==r.textbox&&r.quill.hasFocus()&&r.hide()}),r}return l(e,t),s(e,[{key:"listen",value:function(){var t=this;a(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"listen",this).call(this),this.root.querySelector(".ql-close").addEventListener("click",function(){t.root.classList.remove("ql-editing")}),this.quill.on(h.default.events.SCROLL_OPTIMIZE,function(){setTimeout(function(){if(!t.root.classList.contains("ql-hidden")){var e=t.quill.getSelection();null!=e&&t.position(t.quill.getBounds(e))}},1)})}},{key:"cancel",value:function(){this.show()}},{key:"position",value:function(t){var n=a(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"position",this).call(this,t),r=this.root.querySelector(".ql-tooltip-arrow");if(r.style.marginLeft="",0===n)return n;r.style.marginLeft=-1*n-r.offsetWidth/2+"px"}}]),e}(p.BaseTooltip);_.TEMPLATE=['','
','','',"
"].join(""),e.BubbleTooltip=_,e.default=m},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),s=function t(e,n,r){null===e&&(e=Function.prototype);var o=Object.getOwnPropertyDescriptor(e,n);if(void 0===o){var i=Object.getPrototypeOf(e);return null===i?void 0:t(i,n,r)}if("value"in o)return o.value;var l=o.get;if(void 0!==l)return l.call(r)},u=function(){function t(t,e){for(var n=0;n','','',''].join(""),e.default=w}]).default}); +//# sourceMappingURL=quill.min.js.map \ No newline at end of file diff --git a/lib/assets/strings/ar.json b/lib/assets/strings/ar.json index a589307..ae9c5a5 100644 --- a/lib/assets/strings/ar.json +++ b/lib/assets/strings/ar.json @@ -4,8 +4,6 @@ "ALL": "الكل", "ATTACHED_FILE": "ملف مرفق", "ATTACH_MAXSIZE_VALIDATE": "يجب أن يكون حجم الملف أقل من {0}", - "AUDIO_FILE_OR_URL_MSG": "يرجى إما اختيار ملف صوتي أو إدخال عنوان URL لملف صوتي!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "الرجاء إدخال إما ملف صوتي أو عنوان URL صوتي ، وليس كلاهما!", "Blur": "طمس", "Blur Radius": "نصف القطر الضبابي", "Brush": "فرشاة", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "نص", "ENTER": "يدخل", "ESCAPE": "يهرب", - "Emoji": "رمز تعبيري", + "Emoji": "الرموز التعبيرية", "FILE": "ملف", "FILE_COMPRESSING_ER": "حدث خطأ أثناء ضغط الملف", "FILE_DUPLICATE_ER": "الملف مرفق بالفعل. الرجاء اختيار ملف مختلف", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "ألفا السفلى", "LOWER_ROMAN": "الرومان السفلي", "MAX_ATTACH_MSG": "تم الوصول إلى الحد الأقصى للمرفقات", + "MEDIA_ERROR": "حدث خطأ أثناء تحميل الوسائط.", "MONTH": "شهر", "NO_RESULTS": "لا نتائج", "NUMBERED": "مرقمة", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "افتح في نافذة جديدة", "PICK_GIF": "اختر صورة متحركة", "PICK_IMAGE": "اختر صورة", + "READ_LESS": "أقرأ أقل", + "READ_MORE": "اقرأ أكثر", "REDO_MSG": "أعد تنفيذ الأمر الأخير", "REMOVE": "إزالة", "RESET": "إعادة تعيين", @@ -119,6 +120,7 @@ "Slider White Black Color": "المنزلق أبيض اللون الأسود", "Square": "مربع", "TAB": "فاتورة غير مدفوعة", + "TABLE_CONTENT": "انقر لرؤية محتوى الجدول", "TEXT_TO_DISPLAY": "النص المراد عرضه", "TIMES_NEW_ROMAN": "تايمز نيو رومان", "TITLE_CASE": "حالة العنوان", diff --git a/lib/assets/strings/bg.json b/lib/assets/strings/bg.json index fe3e699..f62db4d 100644 --- a/lib/assets/strings/bg.json +++ b/lib/assets/strings/bg.json @@ -4,8 +4,6 @@ "ALL": "всичко", "ATTACHED_FILE": "Прикачен файл", "ATTACH_MAXSIZE_VALIDATE": "Размерът на файла трябва да е по-малък от {0}", - "AUDIO_FILE_OR_URL_MSG": "Моля, изберете аудио файл или въведете URL адрес на аудио файл!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Моля, въведете аудио файл или URL адрес на аудио, не и двете!", "Blur": "Размазване", "Blur Radius": "Радиус на замъгляване", "Brush": "Четка", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Текст", "ENTER": "ENTER", "ESCAPE": "бягство", - "Emoji": "емотикони", + "Emoji": "Емотикони", "FILE": "досие", "FILE_COMPRESSING_ER": "Възникна грешка при компресиране на файл", "FILE_DUPLICATE_ER": "Файлът вече е прикачен. Моля, изберете друг файл", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Долна Алфа", "LOWER_ROMAN": "Долен римски", "MAX_ATTACH_MSG": "Максималният лимит за прикачени файлове е достигнат", + "MEDIA_ERROR": "Грешка при зареждане на мултимедия.", "MONTH": "месец", "NO_RESULTS": "Няма резултати", "NUMBERED": "Номерирани", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Отвори в нов прозорец", "PICK_GIF": "Изберете Gif", "PICK_IMAGE": "Изберете изображение", + "READ_LESS": "Четете по-малко", + "READ_MORE": "Прочетете още", "REDO_MSG": "Повторете последната команда", "REMOVE": "Премахване", "RESET": "Нулиране", @@ -119,6 +120,7 @@ "Slider White Black Color": "Плъзгач Бял Черен Цвят", "Square": "Квадрат", "TAB": "РАЗДЕЛ", + "TABLE_CONTENT": "Кликнете, за да видите съдържанието на таблицата", "TEXT_TO_DISPLAY": "Текст за показване", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Регистър на заглавието", diff --git a/lib/assets/strings/bs.json b/lib/assets/strings/bs.json index 8e62d8e..5ddccb2 100644 --- a/lib/assets/strings/bs.json +++ b/lib/assets/strings/bs.json @@ -4,8 +4,6 @@ "ALL": "Sve", "ATTACHED_FILE": "Priloženi fajl", "ATTACH_MAXSIZE_VALIDATE": "Veličina fajla mora biti manja od {0}", - "AUDIO_FILE_OR_URL_MSG": "Molimo ili odaberite audio fajl ili unesite URL audio fajla!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Unesite audio fajl ili audio URL, a ne oboje!", "Blur": "Zamućenje", "Blur Radius": "Radijus zamućenja", "Brush": "Četka", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Lower Alpha", "LOWER_ROMAN": "Lower Roman", "MAX_ATTACH_MSG": "Maksimalno ograničenje priloga je dostignuto", + "MEDIA_ERROR": "Greška pri učitavanju medija.", "MONTH": "Mesec", "NO_RESULTS": "Nema rezultata", "NUMBERED": "Numerisano", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Otvori u novom prozoru", "PICK_GIF": "Odaberite Gif", "PICK_IMAGE": "Izaberite sliku", + "READ_LESS": "Čitaj manje", + "READ_MORE": "Čitaj više", "REDO_MSG": "Ponovite zadnju komandu", "REMOVE": "Ukloni", "RESET": "Resetovati", @@ -119,6 +120,7 @@ "Slider White Black Color": "Klizač Bijela Crna Boja", "Square": "Square", "TAB": "TAB", + "TABLE_CONTENT": "Kliknite da vidite sadržaj tabele", "TEXT_TO_DISPLAY": "Tekst za prikaz", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Title Case", diff --git a/lib/assets/strings/cs.json b/lib/assets/strings/cs.json index 5ed3f4b..cdf07ea 100644 --- a/lib/assets/strings/cs.json +++ b/lib/assets/strings/cs.json @@ -4,8 +4,6 @@ "ALL": "Vše", "ATTACHED_FILE": "Přiložený soubor", "ATTACH_MAXSIZE_VALIDATE": "Velikost souboru musí být menší než {0}", - "AUDIO_FILE_OR_URL_MSG": "Vyberte prosím zvukový soubor nebo zadejte adresu URL zvukového souboru!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Zadejte buď zvukový soubor, nebo adresu URL zvuku, nikoli obojí!", "Blur": "Rozmazat", "Blur Radius": "Poloměr rozostření", "Brush": "Štětec", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Text", "ENTER": "ENTER", "ESCAPE": "Uniknout", - "Emoji": "Emotikony", + "Emoji": "Emoji", "FILE": "Soubor", "FILE_COMPRESSING_ER": "Při komprimaci souboru došlo k chybě", "FILE_DUPLICATE_ER": "Soubor je již připojen. Vyberte prosím jiný soubor", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Nižší alfa", "LOWER_ROMAN": "Dolní římská", "MAX_ATTACH_MSG": "Bylo dosaženo maximálního limitu příloh", + "MEDIA_ERROR": "Chyba při načítání média.", "MONTH": "Měsíc", "NO_RESULTS": "Žádné výsledky", "NUMBERED": "Číslovaný", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Otevři v novém okně", "PICK_GIF": "Vyberte Gif", "PICK_IMAGE": "Vyberte obrázek", + "READ_LESS": "Číst méně", + "READ_MORE": "Číst dále", "REDO_MSG": "Opakujte poslední příkaz", "REMOVE": "Odebrat", "RESET": "Resetovat", @@ -119,6 +120,7 @@ "Slider White Black Color": "Posuvník Bílá Černá Barva", "Square": "Náměstí", "TAB": "TAB", + "TABLE_CONTENT": "Kliknutím zobrazíte obsah tabulky", "TEXT_TO_DISPLAY": "Text k zobrazení", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Název případ", diff --git a/lib/assets/strings/da.json b/lib/assets/strings/da.json index ddc4d53..2d0da23 100644 --- a/lib/assets/strings/da.json +++ b/lib/assets/strings/da.json @@ -4,8 +4,6 @@ "ALL": "Alle", "ATTACHED_FILE": "Attached file", "ATTACH_MAXSIZE_VALIDATE": "Filstørrelsen skal være mindre end {0}", - "AUDIO_FILE_OR_URL_MSG": "Vælg venligst enten en lydfil eller indtast en lydfil URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Indtast enten en lydfil eller en lyd-URL, ikke begge!", "Blur": "Blur", "Blur Radius": "Blur Radius", "Brush": "Brush", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Nedre alfa", "LOWER_ROMAN": "Nedre romersk", "MAX_ATTACH_MSG": "Maks. grænse for vedhæftede filer nået", + "MEDIA_ERROR": "Fejl ved indlæsning af medier.", "MONTH": "Måned", "NO_RESULTS": "Ingen resultater", "NUMBERED": "Nummereret", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Åbn i nyt vindue", "PICK_GIF": "Vælg en gif", "PICK_IMAGE": "Pick Image", + "READ_LESS": "Read Less", + "READ_MORE": "Læs mere", "REDO_MSG": "Gentag den sidste kommando", "REMOVE": "Fjern", "RESET": "Nulstil", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider White Black Color", "Square": "Square", "TAB": "TAB", + "TABLE_CONTENT": "Klik for at se tabelindhold", "TEXT_TO_DISPLAY": "Tekst, der skal vises", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titel Case", diff --git a/lib/assets/strings/de.json b/lib/assets/strings/de.json index e7ce7da..a8aee63 100644 --- a/lib/assets/strings/de.json +++ b/lib/assets/strings/de.json @@ -4,8 +4,6 @@ "ALL": "Alle", "ATTACHED_FILE": "Angehängte Datei", "ATTACH_MAXSIZE_VALIDATE": "Die Dateigröße muss kleiner als {0} sein.", - "AUDIO_FILE_OR_URL_MSG": "Bitte wählen Sie entweder eine Audiodatei aus oder geben Sie eine Audiodatei-URL ein!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Bitte geben Sie entweder eine Audiodatei oder eine Audio-URL ein, nicht beides!", "Blur": "Verwischen", "Blur Radius": "Unschärferadius", "Brush": "Bürste", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Unteres Alpha", "LOWER_ROMAN": "Niederrömisch", "MAX_ATTACH_MSG": "Maximales Limit für Anhänge erreicht", + "MEDIA_ERROR": "Fehler beim Laden des Mediums.", "MONTH": "Monat", "NO_RESULTS": "Keine Ergebnisse", "NUMBERED": "Nummeriert", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "In einem neuen Fenster öffnen", "PICK_GIF": "Wählen Sie ein GIF", "PICK_IMAGE": "Bild auswählen", + "READ_LESS": "Weniger lesen", + "READ_MORE": "Mehr lesen", "REDO_MSG": "Wiederholen Sie den letzten Befehl", "REMOVE": "Entfernen", "RESET": "Zurücksetzen", @@ -119,6 +120,7 @@ "Slider White Black Color": "Schieberegler Farbe Weiß Schwarz", "Square": "Quadrat", "TAB": "TAB", + "TABLE_CONTENT": "Klicken Sie hier, um den Tabelleninhalt anzuzeigen", "TEXT_TO_DISPLAY": "Text, der angezeigt werden soll", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titelfall", diff --git a/lib/assets/strings/de_AT.json b/lib/assets/strings/de_AT.json index e7ce7da..a8aee63 100644 --- a/lib/assets/strings/de_AT.json +++ b/lib/assets/strings/de_AT.json @@ -4,8 +4,6 @@ "ALL": "Alle", "ATTACHED_FILE": "Angehängte Datei", "ATTACH_MAXSIZE_VALIDATE": "Die Dateigröße muss kleiner als {0} sein.", - "AUDIO_FILE_OR_URL_MSG": "Bitte wählen Sie entweder eine Audiodatei aus oder geben Sie eine Audiodatei-URL ein!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Bitte geben Sie entweder eine Audiodatei oder eine Audio-URL ein, nicht beides!", "Blur": "Verwischen", "Blur Radius": "Unschärferadius", "Brush": "Bürste", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Unteres Alpha", "LOWER_ROMAN": "Niederrömisch", "MAX_ATTACH_MSG": "Maximales Limit für Anhänge erreicht", + "MEDIA_ERROR": "Fehler beim Laden des Mediums.", "MONTH": "Monat", "NO_RESULTS": "Keine Ergebnisse", "NUMBERED": "Nummeriert", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "In einem neuen Fenster öffnen", "PICK_GIF": "Wählen Sie ein GIF", "PICK_IMAGE": "Bild auswählen", + "READ_LESS": "Weniger lesen", + "READ_MORE": "Mehr lesen", "REDO_MSG": "Wiederholen Sie den letzten Befehl", "REMOVE": "Entfernen", "RESET": "Zurücksetzen", @@ -119,6 +120,7 @@ "Slider White Black Color": "Schieberegler Farbe Weiß Schwarz", "Square": "Quadrat", "TAB": "TAB", + "TABLE_CONTENT": "Klicken Sie hier, um den Tabelleninhalt anzuzeigen", "TEXT_TO_DISPLAY": "Text, der angezeigt werden soll", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titelfall", diff --git a/lib/assets/strings/de_BE.json b/lib/assets/strings/de_BE.json index 98a4206..1b83260 100644 --- a/lib/assets/strings/de_BE.json +++ b/lib/assets/strings/de_BE.json @@ -4,8 +4,6 @@ "ALL": "Alle", "ATTACHED_FILE": "Angehängte Datei", "ATTACH_MAXSIZE_VALIDATE": "Die Dateigröße muss kleiner als {0} sein.", - "AUDIO_FILE_OR_URL_MSG": "Bitte wählen Sie entweder eine Audiodatei aus oder geben Sie eine Audiodatei-URL ein!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Bitte geben Sie entweder eine Audiodatei oder eine Audio-URL ein, nicht beides!", "Blur": "Verwischen", "Blur Radius": "Unschärferadius", "Brush": "Bürste", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Unteres Alpha", "LOWER_ROMAN": "Niederrömisch", "MAX_ATTACH_MSG": "Maximales Limit für Anhänge erreicht", + "MEDIA_ERROR": "Fehler beim Laden des Mediums.", "MONTH": "Monat", "NO_RESULTS": "Keine Ergebnisse", "NUMBERED": "Nummeriert", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "In einem neuen Fenster öffnen", "PICK_GIF": "Wählen Sie ein GIF", "PICK_IMAGE": "Bild auswählen", + "READ_LESS": "Lese weniger", + "READ_MORE": "Weiterlesen", "REDO_MSG": "Wiederholen Sie den letzten Befehl", "REMOVE": "Entfernen", "RESET": "Zurücksetzen", @@ -119,6 +120,7 @@ "Slider White Black Color": "Schieberegler Farbe Weiß Schwarz", "Square": "Quadrat", "TAB": "TAB", + "TABLE_CONTENT": "Klicken Sie hier, um den Tabelleninhalt anzuzeigen", "TEXT_TO_DISPLAY": "Text, der angezeigt werden soll", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titelfall", diff --git a/lib/assets/strings/de_CH.json b/lib/assets/strings/de_CH.json index 43a5541..134cfc5 100644 --- a/lib/assets/strings/de_CH.json +++ b/lib/assets/strings/de_CH.json @@ -4,8 +4,6 @@ "ALL": "Alle", "ATTACHED_FILE": "Angehängte Datei", "ATTACH_MAXSIZE_VALIDATE": "Die Dateigröße muss kleiner als {0} sein.", - "AUDIO_FILE_OR_URL_MSG": "Bitte wählen Sie entweder eine Audiodatei aus oder geben Sie eine Audiodatei-URL ein!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Bitte geben Sie entweder eine Audiodatei oder eine Audio-URL ein, nicht beides!", "Blur": "Verwischen", "Blur Radius": "Unschärferadius", "Brush": "Bürste", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Unteres Alpha", "LOWER_ROMAN": "Niederrömisch", "MAX_ATTACH_MSG": "Maximales Limit für Anhänge erreicht", + "MEDIA_ERROR": "Fehler beim Laden des Mediums.", "MONTH": "Monat", "NO_RESULTS": "Keine Ergebnisse", "NUMBERED": "Nummeriert", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "In einem neuen Fenster öffnen", "PICK_GIF": "Wählen Sie ein GIF", "PICK_IMAGE": "Bild auswählen", + "READ_LESS": "Lese weniger", + "READ_MORE": "Weiterlesen", "REDO_MSG": "Wiederholen Sie den letzten Befehl", "REMOVE": "Entfernen", "RESET": "Zurücksetzen", @@ -119,6 +120,7 @@ "Slider White Black Color": "Schieberegler Farbe Weiß Schwarz", "Square": "Quadrat", "TAB": "TAB", + "TABLE_CONTENT": "Klicken Sie hier, um den Tabelleninhalt anzuzeigen", "TEXT_TO_DISPLAY": "Text, der angezeigt werden soll", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titelfall", diff --git a/lib/assets/strings/el.json b/lib/assets/strings/el.json index 96e9a4b..4cfde82 100644 --- a/lib/assets/strings/el.json +++ b/lib/assets/strings/el.json @@ -4,8 +4,6 @@ "ALL": "Ολα", "ATTACHED_FILE": "Συνημμένο αρχείο", "ATTACH_MAXSIZE_VALIDATE": "Το μέγεθος του αρχείου πρέπει να είναι μικρότερο από {0}", - "AUDIO_FILE_OR_URL_MSG": "Επιλέξτε ένα αρχείο ήχου ή εισαγάγετε μια διεύθυνση URL αρχείου ήχου!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Εισαγάγετε είτε ένα αρχείο ήχου είτε μια διεύθυνση URL ήχου, όχι και τα δύο!", "Blur": "Θολούρα", "Blur Radius": "Ακτίνα θολώματος", "Brush": "Βούρτσα", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Κάτω Άλφα", "LOWER_ROMAN": "Κάτω Ρωμαϊκή", "MAX_ATTACH_MSG": "Συμπληρώθηκε το μέγιστο όριο συνημμένου", + "MEDIA_ERROR": "Σφάλμα κατά τη φόρτωση μέσων.", "MONTH": "Μήνας", "NO_RESULTS": "Χωρίς αποτέλεσμα", "NUMBERED": "Αριθμημένο", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Ανοιξε σε νέο παράθυρο", "PICK_GIF": "Επιλέξτε ένα Gif", "PICK_IMAGE": "Επιλέξτε εικόνα", + "READ_LESS": "Διαβάστε Λιγότερα", + "READ_MORE": "Διαβάστε περισσότερα", "REDO_MSG": "Επαναλάβετε την τελευταία εντολή", "REMOVE": "Αφαιρώ", "RESET": "Επαναφορά", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider Λευκό Μαύρο Χρώμα", "Square": "τετράγωνο", "TAB": "ΑΥΤΙ", + "TABLE_CONTENT": "Κάντε κλικ για να δείτε το περιεχόμενο του πίνακα", "TEXT_TO_DISPLAY": "Κείμενο προς εμφάνιση", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Υπόθεση τίτλου", diff --git a/lib/assets/strings/en.json b/lib/assets/strings/en.json index f8c6cad..9b8f589 100644 --- a/lib/assets/strings/en.json +++ b/lib/assets/strings/en.json @@ -4,8 +4,6 @@ "ALL": "All", "ATTACHED_FILE": "Attached file", "ATTACH_MAXSIZE_VALIDATE": "File size must be less than {0}", - "AUDIO_FILE_OR_URL_MSG": "Please either choose an audio file or enter an audio file URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Please input either an audio file or an audio URL, not both!", "Blur": "Blur", "Blur Radius": "Blur Radius", "Brush": "Brush", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Lower Alpha", "LOWER_ROMAN": "Lower Roman", "MAX_ATTACH_MSG": "Attachment max limit reached", + "MEDIA_ERROR": "Error loading media.", "MONTH": "Month", "NO_RESULTS": "No results", "NUMBERED": "Numbered", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Open in new window", "PICK_GIF": "Pick a Gif", "PICK_IMAGE": "Pick Image", + "READ_LESS": "Read Less", + "READ_MORE": "Read More", "REDO_MSG": "Redo the last command", "REMOVE": "Remove", "RESET": "Reset", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider White Black Color", "Square": "Square", "TAB": "TAB", + "TABLE_CONTENT": "Click to see table content", "TEXT_TO_DISPLAY": "Text to display", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Title Case", diff --git a/lib/assets/strings/en_CA.json b/lib/assets/strings/en_CA.json index f8c6cad..9b8f589 100644 --- a/lib/assets/strings/en_CA.json +++ b/lib/assets/strings/en_CA.json @@ -4,8 +4,6 @@ "ALL": "All", "ATTACHED_FILE": "Attached file", "ATTACH_MAXSIZE_VALIDATE": "File size must be less than {0}", - "AUDIO_FILE_OR_URL_MSG": "Please either choose an audio file or enter an audio file URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Please input either an audio file or an audio URL, not both!", "Blur": "Blur", "Blur Radius": "Blur Radius", "Brush": "Brush", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Lower Alpha", "LOWER_ROMAN": "Lower Roman", "MAX_ATTACH_MSG": "Attachment max limit reached", + "MEDIA_ERROR": "Error loading media.", "MONTH": "Month", "NO_RESULTS": "No results", "NUMBERED": "Numbered", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Open in new window", "PICK_GIF": "Pick a Gif", "PICK_IMAGE": "Pick Image", + "READ_LESS": "Read Less", + "READ_MORE": "Read More", "REDO_MSG": "Redo the last command", "REMOVE": "Remove", "RESET": "Reset", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider White Black Color", "Square": "Square", "TAB": "TAB", + "TABLE_CONTENT": "Click to see table content", "TEXT_TO_DISPLAY": "Text to display", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Title Case", diff --git a/lib/assets/strings/en_GB.json b/lib/assets/strings/en_GB.json index 0f01046..4a9e679 100644 --- a/lib/assets/strings/en_GB.json +++ b/lib/assets/strings/en_GB.json @@ -4,8 +4,6 @@ "ALL": "All", "ATTACHED_FILE": "Attached file", "ATTACH_MAXSIZE_VALIDATE": "File size must be less than {0}", - "AUDIO_FILE_OR_URL_MSG": "Please either choose an audio file or enter an audio file URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Please input either an audio file or an audio URL, not both!", "Blur": "Blur", "Blur Radius": "Blur Radius", "Brush": "Brush", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Lower Alpha", "LOWER_ROMAN": "Lower Roman", "MAX_ATTACH_MSG": "Attachment max limit reached", + "MEDIA_ERROR": "Error loading media.", "MONTH": "Month", "NO_RESULTS": "No results", "NUMBERED": "Numbered", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Open in new window", "PICK_GIF": "Pick a Gif", "PICK_IMAGE": "Pick Image", + "READ_LESS": "Read Less", + "READ_MORE": "Read More", "REDO_MSG": "Redo the last command", "REMOVE": "Remove", "RESET": "Reset", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider White Black Colour", "Square": "Square", "TAB": "TAB", + "TABLE_CONTENT": "Click to see table content", "TEXT_TO_DISPLAY": "Text to display", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Title Case", diff --git a/lib/assets/strings/es.json b/lib/assets/strings/es.json index 98e83fc..51037d8 100644 --- a/lib/assets/strings/es.json +++ b/lib/assets/strings/es.json @@ -4,8 +4,6 @@ "ALL": "Todos", "ATTACHED_FILE": "Archivo adjunto", "ATTACH_MAXSIZE_VALIDATE": "El tamaño del archivo debe ser inferior a {0}", - "AUDIO_FILE_OR_URL_MSG": "¡Elija un archivo de audio o ingrese una URL de archivo de audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ingrese un archivo de audio o una URL de audio, ¡no ambos!", "Blur": "Difuminar", "Blur Radius": "Radio de desenfoque", "Brush": "Cepillar", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texto", "ENTER": "INGRESAR", "ESCAPE": "Escapar", - "Emoji": "Emoji", + "Emoji": "emojis", "FILE": "Archivo", "FILE_COMPRESSING_ER": "Ocurrió un error al comprimir un archivo", "FILE_DUPLICATE_ER": "El archivo ya está adjunto. Por favor, elija un archivo diferente", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "alfa inferior", "LOWER_ROMAN": "bajo romano", "MAX_ATTACH_MSG": "Límite máximo de archivos adjuntos alcanzado", + "MEDIA_ERROR": "Error al cargar medios.", "MONTH": "Mes", "NO_RESULTS": "No hay resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir en Nueva ventana", "PICK_GIF": "elige un gif", "PICK_IMAGE": "Elegir imagen", + "READ_LESS": "Leer menos", + "READ_MORE": "Lee mas", "REDO_MSG": "Rehacer el último comando", "REMOVE": "Eliminar", "RESET": "restaurar", @@ -119,6 +120,7 @@ "Slider White Black Color": "Control deslizante Blanco Negro Color", "Square": "Cuadrado", "TAB": "PESTAÑA", + "TABLE_CONTENT": "Haga clic para ver el contenido de la tabla", "TEXT_TO_DISPLAY": "Texto para mostrar", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titulo del caso", diff --git a/lib/assets/strings/es_CL.json b/lib/assets/strings/es_CL.json index df70f11..cd4ab6b 100644 --- a/lib/assets/strings/es_CL.json +++ b/lib/assets/strings/es_CL.json @@ -4,8 +4,6 @@ "ALL": "Todos", "ATTACHED_FILE": "Archivo adjunto", "ATTACH_MAXSIZE_VALIDATE": "El tamaño del archivo debe ser inferior a {0}", - "AUDIO_FILE_OR_URL_MSG": "¡Elija un archivo de audio o ingrese una URL de archivo de audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ingrese un archivo de audio o una URL de audio, ¡no ambos!", "Blur": "Difuminar", "Blur Radius": "Radio de desenfoque", "Brush": "Cepillar", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texto", "ENTER": "INGRESAR", "ESCAPE": "Escapar", - "Emoji": "Emoji", + "Emoji": "emojis", "FILE": "Archivo", "FILE_COMPRESSING_ER": "Ocurrió un error al comprimir un archivo", "FILE_DUPLICATE_ER": "El archivo ya está adjunto. Por favor, elija un archivo diferente", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "alfa inferior", "LOWER_ROMAN": "bajo romano", "MAX_ATTACH_MSG": "Límite máximo de archivos adjuntos alcanzado", + "MEDIA_ERROR": "Error al cargar medios.", "MONTH": "Mes", "NO_RESULTS": "No hay resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir en Nueva ventana", "PICK_GIF": "elige un gif", "PICK_IMAGE": "Elegir imagen", + "READ_LESS": "Leer menos", + "READ_MORE": "Leer más", "REDO_MSG": "Rehacer el último comando", "REMOVE": "Eliminar", "RESET": "Restablecer", @@ -119,6 +120,7 @@ "Slider White Black Color": "Control deslizante Blanco Negro Color", "Square": "Cuadrado", "TAB": "PESTAÑA", + "TABLE_CONTENT": "Haga clic para ver el contenido de la tabla", "TEXT_TO_DISPLAY": "Texto para mostrar", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titulo del caso", diff --git a/lib/assets/strings/es_EC.json b/lib/assets/strings/es_EC.json index cce73b5..a9af37a 100644 --- a/lib/assets/strings/es_EC.json +++ b/lib/assets/strings/es_EC.json @@ -4,8 +4,6 @@ "ALL": "Todos", "ATTACHED_FILE": "Archivo adjunto", "ATTACH_MAXSIZE_VALIDATE": "El tamaño del archivo debe ser inferior a {0}", - "AUDIO_FILE_OR_URL_MSG": "¡Elija un archivo de audio o ingrese una URL de archivo de audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ingrese un archivo de audio o una URL de audio, ¡no ambos!", "Blur": "Difuminar", "Blur Radius": "Radio de desenfoque", "Brush": "Cepillar", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texto", "ENTER": "INGRESAR", "ESCAPE": "Escapar", - "Emoji": "Emoji", + "Emoji": "emojis", "FILE": "Archivo", "FILE_COMPRESSING_ER": "Ocurrió un error al comprimir un archivo", "FILE_DUPLICATE_ER": "El archivo ya está adjunto. Por favor, elija un archivo diferente", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "alfa inferior", "LOWER_ROMAN": "bajo romano", "MAX_ATTACH_MSG": "Límite máximo de archivos adjuntos alcanzado", + "MEDIA_ERROR": "Error al cargar medios.", "MONTH": "Mes", "NO_RESULTS": "No hay resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir en Nueva ventana", "PICK_GIF": "elige un gif", "PICK_IMAGE": "Elegir imagen", + "READ_LESS": "Leer menos", + "READ_MORE": "Leer más", "REDO_MSG": "Rehacer el último comando", "REMOVE": "Eliminar", "RESET": "Restablecer", @@ -119,6 +120,7 @@ "Slider White Black Color": "Control deslizante Blanco Negro Color", "Square": "Cuadrado", "TAB": "PESTAÑA", + "TABLE_CONTENT": "Haga clic para ver el contenido de la tabla", "TEXT_TO_DISPLAY": "Texto para mostrar", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titulo del caso", diff --git a/lib/assets/strings/es_ES.json b/lib/assets/strings/es_ES.json index 397d55c..4c7798c 100644 --- a/lib/assets/strings/es_ES.json +++ b/lib/assets/strings/es_ES.json @@ -4,8 +4,6 @@ "ALL": "Todo", "ATTACHED_FILE": "Archivo adjunto", "ATTACH_MAXSIZE_VALIDATE": "El tamaño del archivo debe ser inferior a {0}", - "AUDIO_FILE_OR_URL_MSG": "¡Elija un archivo de audio o ingrese una URL de archivo de audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ingrese un archivo de audio o una URL de audio, ¡no ambos!", "Blur": "Difuminar", "Blur Radius": "Radio de desenfoque", "Brush": "Cepillar", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texto", "ENTER": "INGRESAR", "ESCAPE": "Escapar", - "Emoji": "Emoji", + "Emoji": "emojis", "FILE": "Archivo", "FILE_COMPRESSING_ER": "Ocurrió un error al comprimir un archivo", "FILE_DUPLICATE_ER": "El archivo ya está adjunto. Por favor, elija un archivo diferente", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "alfa inferior", "LOWER_ROMAN": "bajo romano", "MAX_ATTACH_MSG": "Límite máximo de archivos adjuntos alcanzado", + "MEDIA_ERROR": "Error al cargar medios.", "MONTH": "Mes", "NO_RESULTS": "No hay resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir en Nueva ventana", "PICK_GIF": "elige un gif", "PICK_IMAGE": "Elegir imagen", + "READ_LESS": "Leer menos", + "READ_MORE": "Leer más", "REDO_MSG": "Rehacer el último comando", "REMOVE": "Eliminar", "RESET": "Restablecer", @@ -119,6 +120,7 @@ "Slider White Black Color": "Control deslizante Blanco Negro Color", "Square": "Cuadrado", "TAB": "PESTAÑA", + "TABLE_CONTENT": "Haga clic para ver el contenido de la tabla", "TEXT_TO_DISPLAY": "Texto para mostrar", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titulo del caso", diff --git a/lib/assets/strings/es_MX.json b/lib/assets/strings/es_MX.json new file mode 100644 index 0000000..51037d8 --- /dev/null +++ b/lib/assets/strings/es_MX.json @@ -0,0 +1,142 @@ +{ + "ACTION": "Acción", + "ADD_URL": "Agregar URL", + "ALL": "Todos", + "ATTACHED_FILE": "Archivo adjunto", + "ATTACH_MAXSIZE_VALIDATE": "El tamaño del archivo debe ser inferior a {0}", + "Blur": "Difuminar", + "Blur Radius": "Radio de desenfoque", + "Brush": "Cepillar", + "CAMERA": "Cámara", + "CANCEL": "Cancelar", + "CHANGE_CASE": "Cambiar caso", + "CHANGE_IMAGE": "Cambiar imagen", + "CHAR_LEFT": "Caracteres restantes {0}", + "CHOOSE_AUDIO": "elegir sonido", + "CHOOSE_COLOR": "Elige un color", + "CHOOSE_FILE": "Elija el archivo", + "CHOOSE_FILE_URL_MSG": "¡Elija un archivo o ingrese una URL de archivo!", + "CHOOSE_IMAGE": "elegir imagen", + "CHOOSE_IMG_URL_MSG": "¡Elija una imagen o ingrese una URL de imagen!", + "CHOOSE_VIDEO": "elegir vídeo", + "CLEAR": "Claro", + "CLOSE": "Cerrar", + "COMPLETE_EDITING": "Edición completa", + "COURIER": "mensajero", + "CROP": "Cosecha", + "CUSTOM": "Personalizado", + "Color Opacity": "Opacidad de color", + "Crop": "Cosecha", + "DEFAULT": "Defecto", + "DELETE": "Borrar", + "DELETE_ATTACHMENT": "Eliminar archivo adjunto", + "DONE": "Terminado", + "EDIT": "Editar", + "EDITOR_CIRCLE": "Circulo", + "EDITOR_CODE": "código", + "EDITOR_DISC": "Desct", + "EDITOR_HEADER_1": "Encabezado 1", + "EDITOR_HEADER_2": "Encabezado 2", + "EDITOR_HEADER_3": "Encabezado 3", + "EDITOR_HEADER_4": "Encabezado 4", + "EDITOR_HEADER_5": "Encabezado 5", + "EDITOR_HEADER_6": "Encabezado 6", + "EDITOR_NORMAL": "normal", + "EDITOR_PT": "punto", + "EDITOR_PX": "px", + "EDITOR_QUOTE": "cita", + "EDITOR_SQUARE": "Cuadrado", + "EDITOR_TEXT": "Texto", + "ENTER": "INGRESAR", + "ESCAPE": "Escapar", + "Emoji": "emojis", + "FILE": "Archivo", + "FILE_COMPRESSING_ER": "Ocurrió un error al comprimir un archivo", + "FILE_DUPLICATE_ER": "El archivo ya está adjunto. Por favor, elija un archivo diferente", + "FILE_OR_URL_MSG": "Ingrese un archivo o una URL de archivo, ¡no ambos!", + "FILE_PIXEL_SIZE_ER": "El tamaño de píxel del archivo debe ser inferior a {0}", + "FILE_PROCESSING_ER": "Ocurrió un error al procesar un archivo", + "FILE_SIZE_CALCULATING_ER": "Se produjo un error al calcular el tamaño de un archivo", + "FILE_UNSUPPORTED": "Este tipo de archivo no está permitido", + "FLIP": "Voltear", + "FROM": "De", + "Filter": "Filtro", + "Flip": "Voltear", + "Freeform": "Forma libre", + "GALLERY": "Galería", + "GIF": "Gif", + "HELP": "Ayuda", + "HIDE": "Ocultar", + "IMAGE_OR_URL_MSG": "Ingrese una imagen o una URL de imagen, ¡no ambas!", + "IMAGE_PICKER_SEMANTIC_SELECTED": "Selector de imágenes. Imagen seleccionada", + "IMAGE_PICKER_SEMANTIC_UNSELECTED": "Selector de imágenes. Ninguna imagen seleccionada", + "IMG_URL_MSG": "¡Por favor ingrese una URL de imagen!", + "INSERT_AUDIO": "Insertar audio", + "INSERT_FILE": "Insertar archivo", + "INSERT_IMAGE": "Insertar imagen", + "INSERT_LINK": "Insertar el link", + "INSERT_PARAGRAPH": "Insertar párrafo", + "INSERT_TABLE": "Insertar tabla", + "INSERT_VIDEO": "Insertar vídeo", + "Insert Your Message": "Inserta tu mensaje", + "KEY_COMBINATION": "combinación de teclas", + "LINK": "Enlace", + "LINK_NAME": "Nombre del enlace", + "LINK_URL": "URL del enlace", + "LOWERCASE": "minúsculas", + "LOWER_ALPHA": "alfa inferior", + "LOWER_ROMAN": "bajo romano", + "MAX_ATTACH_MSG": "Límite máximo de archivos adjuntos alcanzado", + "MEDIA_ERROR": "Error al cargar medios.", + "MONTH": "Mes", + "NO_RESULTS": "No hay resultados", + "NUMBERED": "Numerado", + "OK": "OK", + "OPEN_IN_NEW_WINDOW": "Abrir en Nueva ventana", + "PICK_GIF": "elige un gif", + "PICK_IMAGE": "Elegir imagen", + "READ_LESS": "Leer menos", + "READ_MORE": "Lee mas", + "REDO_MSG": "Rehacer el último comando", + "REMOVE": "Eliminar", + "RESET": "restaurar", + "REST_COLOR_MSG": "Restablecer al color predeterminado", + "ROTATE_LEFT": "Girar a la izquierda", + "ROTATE_RIGHT": "Gira a la derecha", + "Reset": "restaurar", + "Rotate left": "Girar a la izquierda", + "Rotate right": "Gira a la derecha", + "SANS_SERIF": "sans serif", + "SAVE": "Guardar", + "SEARCH_GIF": "Buscar todos los GIF", + "SELECT_FROM_FILES": "Seleccionar de archivos", + "SELECT_STL_MSG": "Seleccionar estilo de lista", + "SENTENCE_CASE": "Caso de sentencia", + "SET_COLOR": "Establecer color", + "SHOW": "Mostrar", + "SWIPE_TO_REVEAL_SEMANTIC": "Desliza hacia la izquierda para revelar acciones", + "Select Emoji": "Seleccionar emoji", + "Slider Color": "Color del control deslizante", + "Slider White Black Color": "Control deslizante Blanco Negro Color", + "Square": "Cuadrado", + "TAB": "PESTAÑA", + "TABLE_CONTENT": "Haga clic para ver el contenido de la tabla", + "TEXT_TO_DISPLAY": "Texto para mostrar", + "TIMES_NEW_ROMAN": "Times New Roman", + "TITLE_CASE": "Titulo del caso", + "TO": "A", + "Text": "Texto", + "UNDO_MSG": "Deshacer el último comando", + "UNKNOWN": "Desconocido", + "UNTAB": "desabrochar", + "UPPERCASE": "MAYÚSCULAS", + "UPPER_ALPHA": "alfa superior", + "UPPER_ROMAN": "romano superior", + "URL": "URL", + "URL_DUPLICATE_ER": "La URL ya está adjunta. Ingrese una URL diferente", + "URL_INVALID_ER": "Introduce una URL válida", + "URL_MSG": "¡Por favor ingrese una URL!", + "VIDEO": "Vídeo", + "VIEW": "Vista", + "WEEK": "Semana" +} \ No newline at end of file diff --git a/lib/assets/strings/es_PE.json b/lib/assets/strings/es_PE.json index cce73b5..a9af37a 100644 --- a/lib/assets/strings/es_PE.json +++ b/lib/assets/strings/es_PE.json @@ -4,8 +4,6 @@ "ALL": "Todos", "ATTACHED_FILE": "Archivo adjunto", "ATTACH_MAXSIZE_VALIDATE": "El tamaño del archivo debe ser inferior a {0}", - "AUDIO_FILE_OR_URL_MSG": "¡Elija un archivo de audio o ingrese una URL de archivo de audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ingrese un archivo de audio o una URL de audio, ¡no ambos!", "Blur": "Difuminar", "Blur Radius": "Radio de desenfoque", "Brush": "Cepillar", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texto", "ENTER": "INGRESAR", "ESCAPE": "Escapar", - "Emoji": "Emoji", + "Emoji": "emojis", "FILE": "Archivo", "FILE_COMPRESSING_ER": "Ocurrió un error al comprimir un archivo", "FILE_DUPLICATE_ER": "El archivo ya está adjunto. Por favor, elija un archivo diferente", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "alfa inferior", "LOWER_ROMAN": "bajo romano", "MAX_ATTACH_MSG": "Límite máximo de archivos adjuntos alcanzado", + "MEDIA_ERROR": "Error al cargar medios.", "MONTH": "Mes", "NO_RESULTS": "No hay resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir en Nueva ventana", "PICK_GIF": "elige un gif", "PICK_IMAGE": "Elegir imagen", + "READ_LESS": "Leer menos", + "READ_MORE": "Leer más", "REDO_MSG": "Rehacer el último comando", "REMOVE": "Eliminar", "RESET": "Restablecer", @@ -119,6 +120,7 @@ "Slider White Black Color": "Control deslizante Blanco Negro Color", "Square": "Cuadrado", "TAB": "PESTAÑA", + "TABLE_CONTENT": "Haga clic para ver el contenido de la tabla", "TEXT_TO_DISPLAY": "Texto para mostrar", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titulo del caso", diff --git a/lib/assets/strings/es_PR.json b/lib/assets/strings/es_PR.json index cce73b5..a9af37a 100644 --- a/lib/assets/strings/es_PR.json +++ b/lib/assets/strings/es_PR.json @@ -4,8 +4,6 @@ "ALL": "Todos", "ATTACHED_FILE": "Archivo adjunto", "ATTACH_MAXSIZE_VALIDATE": "El tamaño del archivo debe ser inferior a {0}", - "AUDIO_FILE_OR_URL_MSG": "¡Elija un archivo de audio o ingrese una URL de archivo de audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ingrese un archivo de audio o una URL de audio, ¡no ambos!", "Blur": "Difuminar", "Blur Radius": "Radio de desenfoque", "Brush": "Cepillar", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texto", "ENTER": "INGRESAR", "ESCAPE": "Escapar", - "Emoji": "Emoji", + "Emoji": "emojis", "FILE": "Archivo", "FILE_COMPRESSING_ER": "Ocurrió un error al comprimir un archivo", "FILE_DUPLICATE_ER": "El archivo ya está adjunto. Por favor, elija un archivo diferente", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "alfa inferior", "LOWER_ROMAN": "bajo romano", "MAX_ATTACH_MSG": "Límite máximo de archivos adjuntos alcanzado", + "MEDIA_ERROR": "Error al cargar medios.", "MONTH": "Mes", "NO_RESULTS": "No hay resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir en Nueva ventana", "PICK_GIF": "elige un gif", "PICK_IMAGE": "Elegir imagen", + "READ_LESS": "Leer menos", + "READ_MORE": "Leer más", "REDO_MSG": "Rehacer el último comando", "REMOVE": "Eliminar", "RESET": "Restablecer", @@ -119,6 +120,7 @@ "Slider White Black Color": "Control deslizante Blanco Negro Color", "Square": "Cuadrado", "TAB": "PESTAÑA", + "TABLE_CONTENT": "Haga clic para ver el contenido de la tabla", "TEXT_TO_DISPLAY": "Texto para mostrar", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titulo del caso", diff --git a/lib/assets/strings/es_UY.json b/lib/assets/strings/es_UY.json index cce73b5..a9af37a 100644 --- a/lib/assets/strings/es_UY.json +++ b/lib/assets/strings/es_UY.json @@ -4,8 +4,6 @@ "ALL": "Todos", "ATTACHED_FILE": "Archivo adjunto", "ATTACH_MAXSIZE_VALIDATE": "El tamaño del archivo debe ser inferior a {0}", - "AUDIO_FILE_OR_URL_MSG": "¡Elija un archivo de audio o ingrese una URL de archivo de audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ingrese un archivo de audio o una URL de audio, ¡no ambos!", "Blur": "Difuminar", "Blur Radius": "Radio de desenfoque", "Brush": "Cepillar", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texto", "ENTER": "INGRESAR", "ESCAPE": "Escapar", - "Emoji": "Emoji", + "Emoji": "emojis", "FILE": "Archivo", "FILE_COMPRESSING_ER": "Ocurrió un error al comprimir un archivo", "FILE_DUPLICATE_ER": "El archivo ya está adjunto. Por favor, elija un archivo diferente", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "alfa inferior", "LOWER_ROMAN": "bajo romano", "MAX_ATTACH_MSG": "Límite máximo de archivos adjuntos alcanzado", + "MEDIA_ERROR": "Error al cargar medios.", "MONTH": "Mes", "NO_RESULTS": "No hay resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir en Nueva ventana", "PICK_GIF": "elige un gif", "PICK_IMAGE": "Elegir imagen", + "READ_LESS": "Leer menos", + "READ_MORE": "Leer más", "REDO_MSG": "Rehacer el último comando", "REMOVE": "Eliminar", "RESET": "Restablecer", @@ -119,6 +120,7 @@ "Slider White Black Color": "Control deslizante Blanco Negro Color", "Square": "Cuadrado", "TAB": "PESTAÑA", + "TABLE_CONTENT": "Haga clic para ver el contenido de la tabla", "TEXT_TO_DISPLAY": "Texto para mostrar", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titulo del caso", diff --git a/lib/assets/strings/fi.json b/lib/assets/strings/fi.json index 4672d16..2b842dd 100644 --- a/lib/assets/strings/fi.json +++ b/lib/assets/strings/fi.json @@ -4,8 +4,6 @@ "ALL": "Kaikki", "ATTACHED_FILE": "Liitetiedosto", "ATTACH_MAXSIZE_VALIDATE": "Tiedoston koon on oltava pienempi kuin {0}", - "AUDIO_FILE_OR_URL_MSG": "Ole hyvä ja valitse äänitiedosto tai anna äänitiedoston URL-osoite!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Syötä joko äänitiedosto tai äänen URL-osoite, älä molempia!", "Blur": "Hämärtää", "Blur Radius": "Sumennuksen säde", "Brush": "Harjata", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alempi Alfa", "LOWER_ROMAN": "Alempi roomalainen", "MAX_ATTACH_MSG": "Liitteen enimmäisraja saavutettu", + "MEDIA_ERROR": "Virhe ladattaessa mediaa.", "MONTH": "Kuukausi", "NO_RESULTS": "Ei tuloksia", "NUMBERED": "Numeroitu", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Avaa uudessa ikkunassa", "PICK_GIF": "Valitse Gif", "PICK_IMAGE": "Valitse kuva", + "READ_LESS": "Lue vähemmän", + "READ_MORE": "Lue lisää", "REDO_MSG": "Toista viimeinen komento", "REMOVE": "Poista", "RESET": "Nollaa", @@ -119,6 +120,7 @@ "Slider White Black Color": "Liukusäädin Valkoinen Musta Väri", "Square": "Neliö", "TAB": "TAB", + "TABLE_CONTENT": "Napsauta nähdäksesi taulukon sisällön", "TEXT_TO_DISPLAY": "Näytettävä teksti", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Otsikkotapaus", diff --git a/lib/assets/strings/fr.json b/lib/assets/strings/fr.json index 2f2b4ca..ff2ee22 100644 --- a/lib/assets/strings/fr.json +++ b/lib/assets/strings/fr.json @@ -4,8 +4,6 @@ "ALL": "Tout", "ATTACHED_FILE": "Pièce jointe", "ATTACH_MAXSIZE_VALIDATE": "La taille du fichier doit être inférieure à {0}", - "AUDIO_FILE_OR_URL_MSG": "Veuillez choisir un fichier audio ou entrer une URL de fichier audio !", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Veuillez saisir soit un fichier audio, soit une URL audio, pas les deux !", "Blur": "Se brouiller", "Blur Radius": "Rayon de flou", "Brush": "Brosse", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texte", "ENTER": "ENTRER", "ESCAPE": "S'échapper", - "Emoji": "Emoji", + "Emoji": "Émoji", "FILE": "Fichier", "FILE_COMPRESSING_ER": "Une erreur s'est produite lors de la compression d'un fichier", "FILE_DUPLICATE_ER": "Le fichier est déjà joint. Veuillez choisir un autre fichier", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alpha inférieur", "LOWER_ROMAN": "Bas-romain", "MAX_ATTACH_MSG": "Limite maximale de pièces jointes atteinte", + "MEDIA_ERROR": "Erreur lors du chargement du support.", "MONTH": "Mois", "NO_RESULTS": "Aucun résultat", "NUMBERED": "Numéroté", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Ouvrir dans une nouvelle fenêtre", "PICK_GIF": "Choisissez un GIF", "PICK_IMAGE": "Choisir une image", + "READ_LESS": "Lire moins", + "READ_MORE": "En savoir plus", "REDO_MSG": "Refaire la dernière commande", "REMOVE": "Supprimer", "RESET": "Réinitialiser", @@ -119,6 +120,7 @@ "Slider White Black Color": "Curseur Blanc Noir Couleur", "Square": "Carré", "TAB": "LANGUETTE", + "TABLE_CONTENT": "Cliquez pour voir le contenu du tableau", "TEXT_TO_DISPLAY": "Texte à afficher", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Casse du titre", diff --git a/lib/assets/strings/fr_BE.json b/lib/assets/strings/fr_BE.json index fbdda32..ef4cbf8 100644 --- a/lib/assets/strings/fr_BE.json +++ b/lib/assets/strings/fr_BE.json @@ -4,8 +4,6 @@ "ALL": "Tout", "ATTACHED_FILE": "Pièce jointe", "ATTACH_MAXSIZE_VALIDATE": "La taille du fichier doit être inférieure à {0}", - "AUDIO_FILE_OR_URL_MSG": "Veuillez choisir un fichier audio ou entrer une URL de fichier audio !", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Veuillez saisir soit un fichier audio, soit une URL audio, pas les deux !", "Blur": "Se brouiller", "Blur Radius": "Rayon de flou", "Brush": "Brosse", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texte", "ENTER": "ENTRER", "ESCAPE": "S'échapper", - "Emoji": "Emoji", + "Emoji": "Émoji", "FILE": "Fichier", "FILE_COMPRESSING_ER": "Une erreur s'est produite lors de la compression d'un fichier", "FILE_DUPLICATE_ER": "Le fichier est déjà joint. Veuillez choisir un autre fichier", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alpha inférieur", "LOWER_ROMAN": "Bas-romain", "MAX_ATTACH_MSG": "Limite maximale de pièces jointes atteinte", + "MEDIA_ERROR": "Erreur lors du chargement du support.", "MONTH": "Mois", "NO_RESULTS": "Aucun résultat", "NUMBERED": "Numéroté", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Ouvrir dans une nouvelle fenêtre", "PICK_GIF": "Choisissez un GIF", "PICK_IMAGE": "Choisir une image", + "READ_LESS": "Lire moins", + "READ_MORE": "Lire la suite", "REDO_MSG": "Refaire la dernière commande", "REMOVE": "Retirer", "RESET": "Réinitialiser", @@ -119,6 +120,7 @@ "Slider White Black Color": "Curseur Blanc Noir Couleur", "Square": "Carré", "TAB": "LANGUETTE", + "TABLE_CONTENT": "Cliquez pour voir le contenu du tableau", "TEXT_TO_DISPLAY": "Texte à afficher", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Casse du titre", diff --git a/lib/assets/strings/fr_CA.json b/lib/assets/strings/fr_CA.json index 028a35a..fb59058 100644 --- a/lib/assets/strings/fr_CA.json +++ b/lib/assets/strings/fr_CA.json @@ -4,8 +4,6 @@ "ALL": "Tous", "ATTACHED_FILE": "Pièce jointe", "ATTACH_MAXSIZE_VALIDATE": "La taille du fichier doit être inférieure à {0}", - "AUDIO_FILE_OR_URL_MSG": "Veuillez choisir un fichier audio ou entrer une URL de fichier audio !", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Veuillez saisir soit un fichier audio, soit une URL audio, pas les deux !", "Blur": "Se brouiller", "Blur Radius": "Rayon de flou", "Brush": "Brosse", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texte", "ENTER": "ENTRER", "ESCAPE": "S'échapper", - "Emoji": "Émoticône", + "Emoji": "Émoji", "FILE": "Fichier", "FILE_COMPRESSING_ER": "Une erreur s'est produite lors de la compression d'un fichier", "FILE_DUPLICATE_ER": "Le fichier est déjà joint. Veuillez choisir un autre fichier", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alpha inférieur", "LOWER_ROMAN": "Bas-romain", "MAX_ATTACH_MSG": "Limite maximale de pièces jointes atteinte", + "MEDIA_ERROR": "Erreur lors du chargement du support.", "MONTH": "Mois", "NO_RESULTS": "Aucun résultat", "NUMBERED": "Numéroté", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Ouvrir dans une nouvelle fenêtre", "PICK_GIF": "Choisissez un GIF", "PICK_IMAGE": "Choisir une image", + "READ_LESS": "Lire moins", + "READ_MORE": "En savoir plus", "REDO_MSG": "Refaire la dernière commande", "REMOVE": "Retirer", "RESET": "Réinitialiser", @@ -119,6 +120,7 @@ "Slider White Black Color": "Curseur Blanc Noir Couleur", "Square": "Carré", "TAB": "LANGUETTE", + "TABLE_CONTENT": "Cliquez pour voir le contenu du tableau", "TEXT_TO_DISPLAY": "Texte à afficher", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Casse du titre", diff --git a/lib/assets/strings/fr_CH.json b/lib/assets/strings/fr_CH.json index fbdda32..ef4cbf8 100644 --- a/lib/assets/strings/fr_CH.json +++ b/lib/assets/strings/fr_CH.json @@ -4,8 +4,6 @@ "ALL": "Tout", "ATTACHED_FILE": "Pièce jointe", "ATTACH_MAXSIZE_VALIDATE": "La taille du fichier doit être inférieure à {0}", - "AUDIO_FILE_OR_URL_MSG": "Veuillez choisir un fichier audio ou entrer une URL de fichier audio !", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Veuillez saisir soit un fichier audio, soit une URL audio, pas les deux !", "Blur": "Se brouiller", "Blur Radius": "Rayon de flou", "Brush": "Brosse", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Texte", "ENTER": "ENTRER", "ESCAPE": "S'échapper", - "Emoji": "Emoji", + "Emoji": "Émoji", "FILE": "Fichier", "FILE_COMPRESSING_ER": "Une erreur s'est produite lors de la compression d'un fichier", "FILE_DUPLICATE_ER": "Le fichier est déjà joint. Veuillez choisir un autre fichier", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alpha inférieur", "LOWER_ROMAN": "Bas-romain", "MAX_ATTACH_MSG": "Limite maximale de pièces jointes atteinte", + "MEDIA_ERROR": "Erreur lors du chargement du support.", "MONTH": "Mois", "NO_RESULTS": "Aucun résultat", "NUMBERED": "Numéroté", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Ouvrir dans une nouvelle fenêtre", "PICK_GIF": "Choisissez un GIF", "PICK_IMAGE": "Choisir une image", + "READ_LESS": "Lire moins", + "READ_MORE": "Lire la suite", "REDO_MSG": "Refaire la dernière commande", "REMOVE": "Retirer", "RESET": "Réinitialiser", @@ -119,6 +120,7 @@ "Slider White Black Color": "Curseur Blanc Noir Couleur", "Square": "Carré", "TAB": "LANGUETTE", + "TABLE_CONTENT": "Cliquez pour voir le contenu du tableau", "TEXT_TO_DISPLAY": "Texte à afficher", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Casse du titre", diff --git a/lib/assets/strings/hr.json b/lib/assets/strings/hr.json index aed68ce..4aceb02 100644 --- a/lib/assets/strings/hr.json +++ b/lib/assets/strings/hr.json @@ -4,8 +4,6 @@ "ALL": "svi", "ATTACHED_FILE": "Priloženi dokument", "ATTACH_MAXSIZE_VALIDATE": "Veličina datoteke mora biti manja od {0}", - "AUDIO_FILE_OR_URL_MSG": "Odaberite audio datoteku ili unesite URL audio datoteke!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Unesite audio datoteku ili audio URL, ne oboje!", "Blur": "Zamutiti", "Blur Radius": "Radijus zamućenja", "Brush": "Četka", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Tekst", "ENTER": "UNESI", "ESCAPE": "Pobjeći", - "Emoji": "emoji", + "Emoji": "Emoji", "FILE": "Datoteka", "FILE_COMPRESSING_ER": "Došlo je do pogreške prilikom sažimanja datoteke", "FILE_DUPLICATE_ER": "Datoteka je već priložena. Odaberite drugu datoteku", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Niža Alfa", "LOWER_ROMAN": "donjorimski", "MAX_ATTACH_MSG": "Dosegnuto je maksimalno ograničenje privitaka", + "MEDIA_ERROR": "Pogreška pri učitavanju medija.", "MONTH": "Mjesec", "NO_RESULTS": "Nema rezultata", "NUMBERED": "Numerirano", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Otvori u novom prozoru", "PICK_GIF": "Odaberite Gif", "PICK_IMAGE": "Odaberite sliku", + "READ_LESS": "Manje čitajte", + "READ_MORE": "Čitaj više", "REDO_MSG": "Ponovi zadnju naredbu", "REMOVE": "Ukloniti", "RESET": "Reset", @@ -119,6 +120,7 @@ "Slider White Black Color": "Klizač Bijela Crna Boja", "Square": "Kvadrat", "TAB": "TAB", + "TABLE_CONTENT": "Kliknite da vidite sadržaj tablice", "TEXT_TO_DISPLAY": "Tekst za prikaz", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Velika i mala slova", diff --git a/lib/assets/strings/hu.json b/lib/assets/strings/hu.json index 2308e64..9ef7d8b 100644 --- a/lib/assets/strings/hu.json +++ b/lib/assets/strings/hu.json @@ -4,8 +4,6 @@ "ALL": "Mind", "ATTACHED_FILE": "Csatolt fájl", "ATTACH_MAXSIZE_VALIDATE": "A fájl méretének kisebbnek kell lennie, mint {0}", - "AUDIO_FILE_OR_URL_MSG": "Kérjük, válasszon hangfájlt, vagy adjon meg egy hangfájl URL-címét!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Kérjük, adjon meg egy hangfájlt vagy egy audio URL-t, ne mindkettőt!", "Blur": "Elhomályosít", "Blur Radius": "Elmosási sugár", "Brush": "Kefe", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alsó alfa", "LOWER_ROMAN": "Alsó római", "MAX_ATTACH_MSG": "Elérte a melléklet maximális korlátját", + "MEDIA_ERROR": "Hiba a média betöltésekor.", "MONTH": "Hónap", "NO_RESULTS": "Nincs eredmény", "NUMBERED": "Számozott", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Megnyitás új ablakban", "PICK_GIF": "Válassz egy GIF-et", "PICK_IMAGE": "Válassza ki a képet", + "READ_LESS": "Kevesebb", + "READ_MORE": "További információ", "REDO_MSG": "Ismételje meg az utolsó parancsot", "REMOVE": "Eltávolítás", "RESET": "Visszaállítás", @@ -119,6 +120,7 @@ "Slider White Black Color": "Csúszka Fehér Fekete Szín", "Square": "Négyzet", "TAB": "TAB", + "TABLE_CONTENT": "Kattintson a táblázat tartalmának megtekintéséhez", "TEXT_TO_DISPLAY": "Megjelenítendő szöveg", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Cím Case", diff --git a/lib/assets/strings/in.json b/lib/assets/strings/in.json index 12bbecb..7c3e123 100644 --- a/lib/assets/strings/in.json +++ b/lib/assets/strings/in.json @@ -4,8 +4,6 @@ "ALL": "Semua", "ATTACHED_FILE": "File terlampir", "ATTACH_MAXSIZE_VALIDATE": "Ukuran berkas harus kurang dari {0}", - "AUDIO_FILE_OR_URL_MSG": "Harap pilih file audio atau masukkan URL file audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Harap masukkan file audio atau URL audio, jangan keduanya!", "Blur": "Mengaburkan", "Blur Radius": "Radius kabur", "Brush": "Sikat", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Teks", "ENTER": "MEMASUKI", "ESCAPE": "Melarikan diri", - "Emoji": "Emoji", + "Emoji": "emoji", "FILE": "Mengajukan", "FILE_COMPRESSING_ER": "Terjadi kesalahan saat mengompresi file", "FILE_DUPLICATE_ER": "File sudah terlampir. Silakan pilih file yang berbeda", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alfa rendah", "LOWER_ROMAN": "Romawi Bawah", "MAX_ATTACH_MSG": "Batas maksimum lampiran tercapai", + "MEDIA_ERROR": "Terjadi kesalahan saat memuat media.", "MONTH": "Bulan", "NO_RESULTS": "Tidak ada hasil", "NUMBERED": "Bernomor", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Buka di jendela baru", "PICK_GIF": "Pilih GIF", "PICK_IMAGE": "Pilih Gambar", + "READ_LESS": "Baca Lebih Sedikit", + "READ_MORE": "Baca selengkapnya", "REDO_MSG": "Ulangi perintah terakhir", "REMOVE": "Menghapus", "RESET": "Setel ulang", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider Warna Putih Hitam", "Square": "Persegi", "TAB": "TAB", + "TABLE_CONTENT": "Klik untuk melihat isi tabel", "TEXT_TO_DISPLAY": "Teks untuk ditampilkan", "TIMES_NEW_ROMAN": "zaman Romawi Baru", "TITLE_CASE": "Kasus Judul", diff --git a/lib/assets/strings/it.json b/lib/assets/strings/it.json index 98872af..6670ec0 100644 --- a/lib/assets/strings/it.json +++ b/lib/assets/strings/it.json @@ -4,8 +4,6 @@ "ALL": "Tutti", "ATTACHED_FILE": "File allegato", "ATTACH_MAXSIZE_VALIDATE": "La dimensione del file deve essere inferiore a {0}", - "AUDIO_FILE_OR_URL_MSG": "Scegli un file audio o inserisci l'URL di un file audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Inserisci un file audio o un URL audio, non entrambi!", "Blur": "Sfocatura", "Blur Radius": "Raggio di sfocatura", "Brush": "Spazzola", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Testo", "ENTER": "ACCEDERE", "ESCAPE": "Fuga", - "Emoji": "emoji", + "Emoji": "Emoji", "FILE": "File", "FILE_COMPRESSING_ER": "Si è verificato un errore durante la compressione di un file", "FILE_DUPLICATE_ER": "Il file è già allegato. Si prega di scegliere un file diverso", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alfa inferiore", "LOWER_ROMAN": "Romano inferiore", "MAX_ATTACH_MSG": "Limite massimo di allegati raggiunto", + "MEDIA_ERROR": "Errore durante il caricamento del supporto.", "MONTH": "Mese", "NO_RESULTS": "Nessun risultato", "NUMBERED": "Numerato", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Apri in una nuova finestra", "PICK_GIF": "Scegli una Gif", "PICK_IMAGE": "Scegli immagine", + "READ_LESS": "Leggi di meno", + "READ_MORE": "Per saperne di più", "REDO_MSG": "Ripeti l'ultimo comando", "REMOVE": "Rimuovere", "RESET": "Ripristina", @@ -119,6 +120,7 @@ "Slider White Black Color": "Cursore Colore Bianco Nero", "Square": "Piazza", "TAB": "TAB", + "TABLE_CONTENT": "Fare clic per visualizzare il contenuto della tabella", "TEXT_TO_DISPLAY": "Testo da visualizzare", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Caso titolo", diff --git a/lib/assets/strings/ja.json b/lib/assets/strings/ja.json index 4bb4b29..6e3dd80 100644 --- a/lib/assets/strings/ja.json +++ b/lib/assets/strings/ja.json @@ -4,8 +4,6 @@ "ALL": "すべて", "ATTACHED_FILE": "添付ファイル", "ATTACH_MAXSIZE_VALIDATE": "ファイルサイズは {0} 未満である必要があります", - "AUDIO_FILE_OR_URL_MSG": "音声ファイルを選択するか、音声ファイルの URL を入力してください。", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "音声ファイルまたは音声 URL の両方ではなく、どちらかを入力してください。", "Blur": "ぼかし", "Blur Radius": "ぼかし半径", "Brush": "みがきます", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "下位アルファ", "LOWER_ROMAN": "ローワーローマン", "MAX_ATTACH_MSG": "アタッチメントの上限に達しました", + "MEDIA_ERROR": "メディアの読み取り失敗。", "MONTH": "月", "NO_RESULTS": "結果がありません", "NUMBERED": "番号付き", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "新しいウィンドウで開きます", "PICK_GIF": "GIF を選択してください", "PICK_IMAGE": "画像を選択", + "READ_LESS": "続きを読む", + "READ_MORE": "続きを読む", "REDO_MSG": "最後のコマンドをやり直す", "REMOVE": "削除する", "RESET": "リセット", @@ -119,6 +120,7 @@ "Slider White Black Color": "スライダー ホワイト ブラック カラー", "Square": "四角", "TAB": "タブ", + "TABLE_CONTENT": "クリックすると表の内容が表示されます", "TEXT_TO_DISPLAY": "表示するテキスト", "TIMES_NEW_ROMAN": "タイムズ ニュー ローマン", "TITLE_CASE": "タイトルケース", diff --git a/lib/assets/strings/ka.json b/lib/assets/strings/ka.json index 3dfed25..76aed27 100644 --- a/lib/assets/strings/ka.json +++ b/lib/assets/strings/ka.json @@ -4,8 +4,6 @@ "ALL": "ყველა", "ATTACHED_FILE": "Მიმაგრებული ფაილი", "ATTACH_MAXSIZE_VALIDATE": "ფაილის ზომა უნდა იყოს {0}-ზე ნაკლები", - "AUDIO_FILE_OR_URL_MSG": "გთხოვთ ან აირჩიოთ აუდიო ფაილი ან შეიყვანოთ აუდიო ფაილის URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "გთხოვთ შეიყვანოთ აუდიო ფაილი ან აუდიო URL და არა ორივე!", "Blur": "დაბინდვა", "Blur Radius": "დაბინდვის რადიუსი", "Brush": "ფუნჯი", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "ტექსტი", "ENTER": "ENTER", "ESCAPE": "გაქცევა", - "Emoji": "ემოჯი", + "Emoji": "Emoji", "FILE": "ფაილი", "FILE_COMPRESSING_ER": "ფაილის შეკუმშვისას მოხდა შეცდომა", "FILE_DUPLICATE_ER": "ფაილი უკვე დართულია. გთხოვთ, აირჩიოთ სხვა ფაილი", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "ქვედა ალფა", "LOWER_ROMAN": "ქვედა რომაული", "MAX_ATTACH_MSG": "მიღწეულია დანართის მაქსიმალური ლიმიტი", + "MEDIA_ERROR": "შეცდომა მედიის ჩატვირთვისას.", "MONTH": "თვე", "NO_RESULTS": "არანაირი შედეგი", "NUMBERED": "დანომრილი", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "გახსენით ახალ ფანჯარაში", "PICK_GIF": "აირჩიე გიფი", "PICK_IMAGE": "აირჩიეთ სურათი", + "READ_LESS": "წაიკითხეთ ნაკლები", + "READ_MORE": "Წაიკითხე მეტი", "REDO_MSG": "გაიმეორეთ ბოლო ბრძანება", "REMOVE": "ამოიღეთ", "RESET": "გადატვირთვა", @@ -119,6 +120,7 @@ "Slider White Black Color": "სლაიდერი თეთრი შავი ფერი", "Square": "მოედანი", "TAB": "TAB", + "TABLE_CONTENT": "დააწკაპუნეთ ცხრილის შინაარსის სანახავად", "TEXT_TO_DISPLAY": "ტექსტი საჩვენებლად", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "სათაურის საქმე", diff --git a/lib/assets/strings/ko.json b/lib/assets/strings/ko.json index aaab22a..07c4e11 100644 --- a/lib/assets/strings/ko.json +++ b/lib/assets/strings/ko.json @@ -4,8 +4,6 @@ "ALL": "모든", "ATTACHED_FILE": "첨부 파일", "ATTACH_MAXSIZE_VALIDATE": "파일 크기는 {0}보다 작아야 합니다.", - "AUDIO_FILE_OR_URL_MSG": "오디오 파일을 선택하거나 오디오 파일 URL을 입력하세요!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "오디오 파일 또는 오디오 URL 중 하나만 입력하세요. 둘 다 입력하면 안 됩니다!", "Blur": "흐림", "Blur Radius": "흐림 반경", "Brush": "브러시", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "낮은 알파", "LOWER_ROMAN": "낮은 로마", "MAX_ATTACH_MSG": "첨부 파일 최대 한도 도달", + "MEDIA_ERROR": "미디어를 로드하는 중에 오류가 발생했습니다.", "MONTH": "달", "NO_RESULTS": "결과 없음", "NUMBERED": "번호가 매겨진", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "새 창에서 열기", "PICK_GIF": "GIF 선택", "PICK_IMAGE": "이미지 선택", + "READ_LESS": "덜 읽기", + "READ_MORE": "더 읽어보기", "REDO_MSG": "마지막 명령 다시 실행", "REMOVE": "풀다", "RESET": "다시 놓기", @@ -119,6 +120,7 @@ "Slider White Black Color": "슬라이더 화이트 블랙 색상", "Square": "정사각형", "TAB": "탭", + "TABLE_CONTENT": "표 내용을 보려면 클릭하세요.", "TEXT_TO_DISPLAY": "표시할 텍스트", "TIMES_NEW_ROMAN": "타임즈 뉴 로만", "TITLE_CASE": "제목 케이스", diff --git a/lib/assets/strings/lt.json b/lib/assets/strings/lt.json index 3a9d921..11487eb 100644 --- a/lib/assets/strings/lt.json +++ b/lib/assets/strings/lt.json @@ -4,8 +4,6 @@ "ALL": "Visi", "ATTACHED_FILE": "Pridedamas failas", "ATTACH_MAXSIZE_VALIDATE": "Failo dydis turi būti mažesnis nei {0}", - "AUDIO_FILE_OR_URL_MSG": "Pasirinkite garso failą arba įveskite garso failo URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Įveskite garso failą arba garso URL, o ne abu!", "Blur": "Suliejimas", "Blur Radius": "Suliejimo spindulys", "Brush": "Šepetys", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Tekstas", "ENTER": "ENTER", "ESCAPE": "Pabegti", - "Emoji": "Jaustukas", + "Emoji": "Jaustukai", "FILE": "Failas", "FILE_COMPRESSING_ER": "Suglaudinant failą įvyko klaida", "FILE_DUPLICATE_ER": "Failas jau pridėtas. Pasirinkite kitą failą", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Žemutinė Alfa", "LOWER_ROMAN": "Žemutinė romėniška", "MAX_ATTACH_MSG": "Pasiektas maksimalus priedo limitas", + "MEDIA_ERROR": "Įkeliant laikmeną įvyko klaida.", "MONTH": "Mėnuo", "NO_RESULTS": "Jokių rezultatų", "NUMBERED": "Sunumeruoti", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Atidaryti naujame lange", "PICK_GIF": "Pasirinkite Gif", "PICK_IMAGE": "Pasirinkite vaizdą", + "READ_LESS": "Skaitykite Mažiau", + "READ_MORE": "Skaityti daugiau", "REDO_MSG": "Pakartokite paskutinę komandą", "REMOVE": "Šalinti", "RESET": "Nustatyti iš naujo", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slankiklis Balta Juoda Spalva", "Square": "Kvadratas", "TAB": "TAB", + "TABLE_CONTENT": "Spustelėkite norėdami pamatyti lentelės turinį", "TEXT_TO_DISPLAY": "Rodomas tekstas", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Pavadinimo byla", diff --git a/lib/assets/strings/lv.json b/lib/assets/strings/lv.json index dfb9ec4..0d3b01e 100644 --- a/lib/assets/strings/lv.json +++ b/lib/assets/strings/lv.json @@ -4,8 +4,6 @@ "ALL": "Visi", "ATTACHED_FILE": "Pievienotais fails", "ATTACH_MAXSIZE_VALIDATE": "Faila lielumam ir jābūt mazākam par {0}", - "AUDIO_FILE_OR_URL_MSG": "Lūdzu, izvēlieties audio failu vai ievadiet audio faila URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Lūdzu, ievadiet audio failu vai audio URL, nevis abus!", "Blur": "Aizmiglot", "Blur Radius": "Aizmiglošanas rādiuss", "Brush": "Ota", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Apakšējā Alfa", "LOWER_ROMAN": "Lejas romiešu", "MAX_ATTACH_MSG": "Sasniegts pielikuma maksimālais ierobežojums", + "MEDIA_ERROR": "Ielādējot datu nesēju, radās kļūda.", "MONTH": "Mēnesis", "NO_RESULTS": "Nav rezultātu", "NUMBERED": "Numurēts", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Atvērt jaunā logā", "PICK_GIF": "Izvēlieties Gif", "PICK_IMAGE": "Izvēlieties attēlu", + "READ_LESS": "Lasi Mazāk", + "READ_MORE": "Lasīt vairāk", "REDO_MSG": "Atkārtojiet pēdējo komandu", "REMOVE": "Noņemt", "RESET": "Atiestatīt", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slīdnis Balts Melns Krāsa", "Square": "Kvadrāts", "TAB": "TAB", + "TABLE_CONTENT": "Noklikšķiniet, lai skatītu tabulas saturu", "TEXT_TO_DISPLAY": "Parādāmais teksts", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Virsraksta lieta", diff --git a/lib/assets/strings/mk.json b/lib/assets/strings/mk.json index a044e1f..602cbad 100644 --- a/lib/assets/strings/mk.json +++ b/lib/assets/strings/mk.json @@ -4,8 +4,6 @@ "ALL": "Сите", "ATTACHED_FILE": "Приложениот документ", "ATTACH_MAXSIZE_VALIDATE": "Големината на датотеката мора да биде помала од {0}", - "AUDIO_FILE_OR_URL_MSG": "Ве молиме или изберете аудио датотека или внесете URL на аудио датотека!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ве молиме внесете аудио датотека или аудио URL, а не и двете!", "Blur": "Заматено", "Blur Radius": "Радиус на заматување", "Brush": "Четка", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Долна Алфа", "LOWER_ROMAN": "долен римски", "MAX_ATTACH_MSG": "Достигнато е максималното ограничување на прилогот", + "MEDIA_ERROR": "Грешка при вчитување медиум.", "MONTH": "Месец", "NO_RESULTS": "Нема резултати", "NUMBERED": "Нумерирани", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Отвори во нов прозорец", "PICK_GIF": "Изберете гиф", "PICK_IMAGE": "Изберете слика", + "READ_LESS": "Читајте помалку", + "READ_MORE": "Прочитај повеќе", "REDO_MSG": "Повторете ја последната команда", "REMOVE": "Отстрани", "RESET": "Ресетирање", @@ -119,6 +120,7 @@ "Slider White Black Color": "Лизгач Бела Црна боја", "Square": "Плоштад", "TAB": "ТАБ", + "TABLE_CONTENT": "Кликнете за да ја видите содржината на табелата", "TEXT_TO_DISPLAY": "Текст за прикажување", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Случај за наслов", diff --git a/lib/assets/strings/nb.json b/lib/assets/strings/nb.json index 98a056c..4a62d61 100644 --- a/lib/assets/strings/nb.json +++ b/lib/assets/strings/nb.json @@ -4,8 +4,6 @@ "ALL": "Alle", "ATTACHED_FILE": "Vedlagt fil", "ATTACH_MAXSIZE_VALIDATE": "Filstørrelsen må være mindre enn {0}", - "AUDIO_FILE_OR_URL_MSG": "Velg enten en lydfil eller skriv inn en lydfil-URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Vennligst skriv inn enten en lydfil eller en lyd-URL, ikke begge!", "Blur": "Uklarhet", "Blur Radius": "Uskarp radius", "Brush": "Børste", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Nedre alfa", "LOWER_ROMAN": "Nedre romersk", "MAX_ATTACH_MSG": "Maksgrensen for vedlegg nådd", + "MEDIA_ERROR": "Feil ved innlasting av media.", "MONTH": "Måned", "NO_RESULTS": "Ingen resultater", "NUMBERED": "Nummerert", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Åpne i nytt vindu", "PICK_GIF": "Velg en gif", "PICK_IMAGE": "Velg bilde", + "READ_LESS": "Les mindre", + "READ_MORE": "Les mer", "REDO_MSG": "Gjenta den siste kommandoen", "REMOVE": "Fjern", "RESET": "Tilbakestill", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider Hvit Svart Farge", "Square": "Torget", "TAB": "TAB", + "TABLE_CONTENT": "Klikk for å se tabellinnhold", "TEXT_TO_DISPLAY": "Tekst som skal vises", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Tittelsak", diff --git a/lib/assets/strings/nl.json b/lib/assets/strings/nl.json index 9782ed9..f252279 100644 --- a/lib/assets/strings/nl.json +++ b/lib/assets/strings/nl.json @@ -4,8 +4,6 @@ "ALL": "Alle", "ATTACHED_FILE": "Bijgevoegd bestand", "ATTACH_MAXSIZE_VALIDATE": "Bestandsgrootte moet kleiner zijn dan {0}", - "AUDIO_FILE_OR_URL_MSG": "Kies een audiobestand of voer de URL van een audiobestand in!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Voer een audiobestand of een audio-URL in, niet beide!", "Blur": "Vervagen", "Blur Radius": "Straal vervagen", "Brush": "Borstel", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Lagere alfa", "LOWER_ROMAN": "Neder-Romeins", "MAX_ATTACH_MSG": "Maximale limiet voor bijlagen bereikt", + "MEDIA_ERROR": "Fout bij het laden van media.", "MONTH": "Maand", "NO_RESULTS": "Geen resultaten", "NUMBERED": "Genummerd", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Openen in een nieuw venster", "PICK_GIF": "Kies een gif", "PICK_IMAGE": "Kies afbeelding", + "READ_LESS": "Minder lezen", + "READ_MORE": "Meer informatie", "REDO_MSG": "Voer de laatste opdracht opnieuw uit", "REMOVE": "Verwijderen", "RESET": "Opnieuw instellen", @@ -119,6 +120,7 @@ "Slider White Black Color": "Schuifregelaar Wit Zwart Kleur", "Square": "Vierkant", "TAB": "TAB", + "TABLE_CONTENT": "Klik om de tabelinhoud te bekijken", "TEXT_TO_DISPLAY": "Tekst om weer te geven", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Hoofdzaak", diff --git a/lib/assets/strings/pl.json b/lib/assets/strings/pl.json index 94908ba..2ae15a5 100644 --- a/lib/assets/strings/pl.json +++ b/lib/assets/strings/pl.json @@ -4,8 +4,6 @@ "ALL": "Wszystkie", "ATTACHED_FILE": "Załączony plik", "ATTACH_MAXSIZE_VALIDATE": "Rozmiar pliku musi być mniejszy niż {0}", - "AUDIO_FILE_OR_URL_MSG": "Wybierz plik audio lub wprowadź adres URL pliku audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Wprowadź plik audio lub adres URL audio, a nie jedno i drugie!", "Blur": "Plama", "Blur Radius": "Promień rozmycia", "Brush": "Szczotka", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Dolna Alfa", "LOWER_ROMAN": "dolny rzymski", "MAX_ATTACH_MSG": "Osiągnięto maksymalny limit załączników", + "MEDIA_ERROR": "Błąd podczas ładowania multimediów.", "MONTH": "Miesiąc", "NO_RESULTS": "Brak wyników", "NUMBERED": "Numerowane", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Otworzyć w nowym oknie", "PICK_GIF": "Wybierz GIF-a", "PICK_IMAGE": "Wybierz obraz", + "READ_LESS": "Mniej czytać", + "READ_MORE": "Czytaj więcej", "REDO_MSG": "Powtórz ostatnie polecenie", "REMOVE": "Usuń", "RESET": "Resetuj", @@ -119,6 +120,7 @@ "Slider White Black Color": "Suwak biały czarny kolor", "Square": "Kwadrat", "TAB": "PATKA", + "TABLE_CONTENT": "Kliknij, żeby zobaczyć zawartość tabeli", "TEXT_TO_DISPLAY": "Tekst do wyświetlenia", "TIMES_NEW_ROMAN": "Czcionka Times New Roman", "TITLE_CASE": "Tytuł sprawy", diff --git a/lib/assets/strings/pt.json b/lib/assets/strings/pt.json index a729037..8dbe1da 100644 --- a/lib/assets/strings/pt.json +++ b/lib/assets/strings/pt.json @@ -4,8 +4,6 @@ "ALL": "Tudo", "ATTACHED_FILE": "Arquivo anexo", "ATTACH_MAXSIZE_VALIDATE": "O tamanho do arquivo deve ser menor que {0}", - "AUDIO_FILE_OR_URL_MSG": "Por favor, escolha um arquivo de áudio ou insira um URL de arquivo de áudio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Insira um arquivo de áudio ou um URL de áudio, não ambos!", "Blur": "Borrão", "Blur Radius": "Raio do desfoque", "Brush": "Escovar", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alfa inferior", "LOWER_ROMAN": "baixo romano", "MAX_ATTACH_MSG": "Limite máximo de anexos atingido", + "MEDIA_ERROR": "Erro ao carregar mídia.", "MONTH": "Mês", "NO_RESULTS": "Sem resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir em nova janela", "PICK_GIF": "Escolha um GIF", "PICK_IMAGE": "Escolher imagem", + "READ_LESS": "Leia menos", + "READ_MORE": "Ler mais", "REDO_MSG": "Refazer o último comando", "REMOVE": "Remover", "RESET": "Reinicializar", @@ -119,6 +120,7 @@ "Slider White Black Color": "Controle deslizante Branco Preto Cor", "Square": "Quadrado", "TAB": "ABA", + "TABLE_CONTENT": "Clique para ver o conteúdo da tabela", "TEXT_TO_DISPLAY": "Texto a ser exibido", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Título", diff --git a/lib/assets/strings/pt_BR.json b/lib/assets/strings/pt_BR.json index 0e3ad7c..d20c4fc 100644 --- a/lib/assets/strings/pt_BR.json +++ b/lib/assets/strings/pt_BR.json @@ -4,8 +4,6 @@ "ALL": "Todos", "ATTACHED_FILE": "Arquivo anexo", "ATTACH_MAXSIZE_VALIDATE": "O tamanho do arquivo deve ser menor que {0}", - "AUDIO_FILE_OR_URL_MSG": "Por favor, escolha um arquivo de áudio ou insira um URL de arquivo de áudio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Insira um arquivo de áudio ou um URL de áudio, não ambos!", "Blur": "Borrão", "Blur Radius": "Raio do desfoque", "Brush": "Escovar", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alfa inferior", "LOWER_ROMAN": "baixo romano", "MAX_ATTACH_MSG": "Limite máximo de anexos atingido", + "MEDIA_ERROR": "Erro ao carregar mídia.", "MONTH": "Mês", "NO_RESULTS": "Sem resultados", "NUMBERED": "Numerado", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Abrir em nova janela", "PICK_GIF": "Escolha um GIF", "PICK_IMAGE": "Escolha a imagem", + "READ_LESS": "Leia menos", + "READ_MORE": "Ler mais", "REDO_MSG": "Refazer o último comando", "REMOVE": "Remover", "RESET": "Redefinir", @@ -119,6 +120,7 @@ "Slider White Black Color": "Controle deslizante Branco Preto Cor", "Square": "Quadrado", "TAB": "ABA", + "TABLE_CONTENT": "Clique para ver o conteúdo da tabela", "TEXT_TO_DISPLAY": "Texto a ser exibido", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Título", diff --git a/lib/assets/strings/ro.json b/lib/assets/strings/ro.json index 1def6b4..af3529b 100644 --- a/lib/assets/strings/ro.json +++ b/lib/assets/strings/ro.json @@ -4,8 +4,6 @@ "ALL": "Toate", "ATTACHED_FILE": "Fisier atasat", "ATTACH_MAXSIZE_VALIDATE": "Dimensiunea fișierului trebuie să fie mai mică de {0}", - "AUDIO_FILE_OR_URL_MSG": "Vă rugăm fie să alegeți un fișier audio, fie să introduceți adresa URL a unui fișier audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Introduceți fie un fișier audio, fie o adresă URL audio, nu ambele!", "Blur": "Estompa", "Blur Radius": "Raza de estompare", "Brush": "Perie", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alfa inferioară", "LOWER_ROMAN": "Romanul de jos", "MAX_ATTACH_MSG": "Limita maximă a atașamentului a fost atinsă", + "MEDIA_ERROR": "Eroare la încărcarea media.", "MONTH": "Lună", "NO_RESULTS": "Fara rezultate", "NUMBERED": "Numerotat", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Deschide într-o fereastră nouă", "PICK_GIF": "Alegeți un Gif", "PICK_IMAGE": "Alegeți imaginea", + "READ_LESS": "Citiți mai puțin", + "READ_MORE": "Citeste mai mult", "REDO_MSG": "Repet ultima comandă", "REMOVE": "Elimina", "RESET": "restabili", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider Alb Negru Culoare", "Square": "Pătrat", "TAB": "TAB", + "TABLE_CONTENT": "Faceți clic pentru a vedea conținutul tabelului", "TEXT_TO_DISPLAY": "Text de afișat", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Cazul de titlu", diff --git a/lib/assets/strings/ru.json b/lib/assets/strings/ru.json index f9369f9..eca8858 100644 --- a/lib/assets/strings/ru.json +++ b/lib/assets/strings/ru.json @@ -4,8 +4,6 @@ "ALL": "Все", "ATTACHED_FILE": "Прикрепленный файл", "ATTACH_MAXSIZE_VALIDATE": "Размер файла должен быть меньше {0}", - "AUDIO_FILE_OR_URL_MSG": "Пожалуйста, выберите аудиофайл или введите URL-адрес аудиофайла!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Пожалуйста, введите либо аудиофайл, либо URL-адрес аудио, но не то и другое одновременно!", "Blur": "Размытие", "Blur Radius": "Радиус размытия", "Brush": "Щетка", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Текст", "ENTER": "ВХОДИТЬ", "ESCAPE": "Побег", - "Emoji": "Emoji", + "Emoji": "Эмодзи", "FILE": "файл", "FILE_COMPRESSING_ER": "Произошла ошибка при сжатии файла", "FILE_DUPLICATE_ER": "Файл уже прикреплен. Пожалуйста, выберите другой файл", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Нижняя Альфа", "LOWER_ROMAN": "Нижний римский", "MAX_ATTACH_MSG": "Достигнуто максимальное количество прикрепленных файлов", + "MEDIA_ERROR": "Ошибка загрузки носителя.", "MONTH": "Месяц", "NO_RESULTS": "Без результатов", "NUMBERED": "Пронумерованный", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Открыть в новом окне", "PICK_GIF": "Выберите гифку", "PICK_IMAGE": "Выбрать изображение", + "READ_LESS": "Читать меньше", + "READ_MORE": "Читать далее", "REDO_MSG": "Повторить последнюю команду", "REMOVE": "Удалить", "RESET": "Сброс", @@ -119,6 +120,7 @@ "Slider White Black Color": "Слайдер Белый Черный Цвет", "Square": "Квадрат", "TAB": "Вкладка", + "TABLE_CONTENT": "Нажмите, чтобы просмотреть содержимое таблицы", "TEXT_TO_DISPLAY": "Текст для отображения", "TIMES_NEW_ROMAN": "Таймс Нью Роман", "TITLE_CASE": "Название дела", diff --git a/lib/assets/strings/sk.json b/lib/assets/strings/sk.json index 4d17b54..e8ec79f 100644 --- a/lib/assets/strings/sk.json +++ b/lib/assets/strings/sk.json @@ -4,8 +4,6 @@ "ALL": "Všetko", "ATTACHED_FILE": "Priložený súbor", "ATTACH_MAXSIZE_VALIDATE": "Veľkosť súboru musí byť menšia ako {0}", - "AUDIO_FILE_OR_URL_MSG": "Vyberte buď zvukový súbor, alebo zadajte adresu URL zvukového súboru!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Zadajte buď zvukový súbor alebo adresu URL zvuku, nie oboje!", "Blur": "Rozmazať", "Blur Radius": "Polomer rozostrenia", "Brush": "Kefa", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Text", "ENTER": "ENTER", "ESCAPE": "uniknúť", - "Emoji": "Emodži", + "Emoji": "Emoji", "FILE": "Súbor", "FILE_COMPRESSING_ER": "Pri komprimácii súboru sa vyskytla chyba", "FILE_DUPLICATE_ER": "Súbor je už pripojený. Vyberte iný súbor", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Dolná alfa", "LOWER_ROMAN": "Dolná rímska", "MAX_ATTACH_MSG": "Bol dosiahnutý maximálny limit príloh", + "MEDIA_ERROR": "Chyba pri načítavaní média.", "MONTH": "Mesiac", "NO_RESULTS": "Žiadne výsledky", "NUMBERED": "Číslované", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Otvoriť v novom okne", "PICK_GIF": "Vyberte Gif", "PICK_IMAGE": "Vyberte obrázok", + "READ_LESS": "Načítať menej", + "READ_MORE": "Prečítať viac", "REDO_MSG": "Zopakujte posledný príkaz", "REMOVE": "Odobrať", "RESET": "Resetovať", @@ -119,6 +120,7 @@ "Slider White Black Color": "Posuvník Biela Čierna Farba", "Square": "Námestie", "TAB": "TAB", + "TABLE_CONTENT": "Kliknutím zobrazíte obsah tabuľky", "TEXT_TO_DISPLAY": "Text na zobrazenie", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Názov prípad", diff --git a/lib/assets/strings/sl.json b/lib/assets/strings/sl.json index f5d0f09..1c8b732 100644 --- a/lib/assets/strings/sl.json +++ b/lib/assets/strings/sl.json @@ -4,8 +4,6 @@ "ALL": "Vse", "ATTACHED_FILE": "Pripeta datoteka", "ATTACH_MAXSIZE_VALIDATE": "Velikost datoteke mora biti manjša od {0}", - "AUDIO_FILE_OR_URL_MSG": "Izberite zvočno datoteko ali vnesite URL zvočne datoteke!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Vnesite zvočno datoteko ali zvočni URL, ne obojega!", "Blur": "Zameglitev", "Blur Radius": "Polmer zameglitve", "Brush": "Čopič", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Besedilo", "ENTER": "ENTER", "ESCAPE": "Pobeg", - "Emoji": "Čustveni simboli", + "Emoji": "Emoji", "FILE": "Datoteka", "FILE_COMPRESSING_ER": "Med stiskanjem datoteke je prišlo do napake", "FILE_DUPLICATE_ER": "Datoteka je že priložena. Izberite drugo datoteko", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Spodnja alfa", "LOWER_ROMAN": "spodnjerimski", "MAX_ATTACH_MSG": "Dosežena je največja omejitev prilog", + "MEDIA_ERROR": "Napaka pri nalaganju medija.", "MONTH": "Mesec", "NO_RESULTS": "Brez rezultatov", "NUMBERED": "Oštevilčeno", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Odpri v novem oknu", "PICK_GIF": "Izberite gif", "PICK_IMAGE": "Izberite sliko", + "READ_LESS": "Preberi manj", + "READ_MORE": "Preberite več", "REDO_MSG": "Ponovite zadnji ukaz", "REMOVE": "Odstrani", "RESET": "Ponastavi", @@ -119,6 +120,7 @@ "Slider White Black Color": "Drsnik bele črne barve", "Square": "kvadrat", "TAB": "TAB", + "TABLE_CONTENT": "Kliknite za ogled vsebine tabele", "TEXT_TO_DISPLAY": "Besedilo za prikaz", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Naslov z velikimi črkami", diff --git a/lib/assets/strings/sq.json b/lib/assets/strings/sq.json index a8c1b53..98e566b 100644 --- a/lib/assets/strings/sq.json +++ b/lib/assets/strings/sq.json @@ -4,8 +4,6 @@ "ALL": "Të gjitha", "ATTACHED_FILE": "Dosja e bashkangjitur", "ATTACH_MAXSIZE_VALIDATE": "Madhësia e skedarit duhet të jetë më e vogël se {0}", - "AUDIO_FILE_OR_URL_MSG": "Ju lutemi zgjidhni një skedar audio ose futni një URL të skedarit audio!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Ju lutemi futni ose një skedar audio ose një URL audio, jo të dyja!", "Blur": "E turbullt", "Blur Radius": "Rrezja e turbullimit", "Brush": "Furçë", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alfa e poshtme", "LOWER_ROMAN": "Romani i Poshtëm", "MAX_ATTACH_MSG": "U arrit kufiri maksimal i bashkëngjitjes", + "MEDIA_ERROR": "Gabim gjatë ngarkimit të medias.", "MONTH": "Muaj", "NO_RESULTS": "Nuk ka rezultate", "NUMBERED": "Të numëruara", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Hapni në dritare të re", "PICK_GIF": "Zgjidh një Gif", "PICK_IMAGE": "Zgjidh imazhin", + "READ_LESS": "Lexo më pak", + "READ_MORE": "Lexo më shumë", "REDO_MSG": "Ribëni komandën e fundit", "REMOVE": "Hiq", "RESET": "Rivendos", @@ -119,6 +120,7 @@ "Slider White Black Color": "Rrëshqitës Bardhë Ngjyra e zezë", "Square": "Sheshi", "TAB": "TAB", + "TABLE_CONTENT": "Klikoni për të parë përmbajtjen e tabelës", "TEXT_TO_DISPLAY": "Teksti për t'u shfaqur", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Rasti i titullit", diff --git a/lib/assets/strings/sr.json b/lib/assets/strings/sr.json index 26a0c5c..2f340cc 100644 --- a/lib/assets/strings/sr.json +++ b/lib/assets/strings/sr.json @@ -4,8 +4,6 @@ "ALL": "Све", "ATTACHED_FILE": "Приложена датотека", "ATTACH_MAXSIZE_VALIDATE": "Величина датотеке мора бити мања од {0}", - "AUDIO_FILE_OR_URL_MSG": "Изаберите аудио датотеку или унесите УРЛ аудио датотеке!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Унесите аудио датотеку или аудио УРЛ, а не обоје!", "Blur": "Блур", "Blur Radius": "Радијус замућења", "Brush": "Четка", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Ловер Алпха", "LOWER_ROMAN": "доњоримски", "MAX_ATTACH_MSG": "Максимално ограничење прилога је достигнуто", + "MEDIA_ERROR": "Грешка при учитавању медија.", "MONTH": "Месец дана", "NO_RESULTS": "Нема резултата", "NUMBERED": "Нумерисано", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Отвори у новом прозору", "PICK_GIF": "Изаберите Гиф", "PICK_IMAGE": "Изаберите слику", + "READ_LESS": "Читај мање", + "READ_MORE": "Опширније", "REDO_MSG": "Поновите последњу команду", "REMOVE": "Уклони", "RESET": "Ресетовање", @@ -119,6 +120,7 @@ "Slider White Black Color": "Клизач Бела Црна Боја", "Square": "Квадрат", "TAB": "ТАБ", + "TABLE_CONTENT": "Кликните да видите садржај табеле", "TEXT_TO_DISPLAY": "Текст за приказ", "TIMES_NEW_ROMAN": "Тимес Нев Роман", "TITLE_CASE": "Титле Цасе", diff --git a/lib/assets/strings/sv.json b/lib/assets/strings/sv.json index 5744bad..1d3202b 100644 --- a/lib/assets/strings/sv.json +++ b/lib/assets/strings/sv.json @@ -4,8 +4,6 @@ "ALL": "Alla", "ATTACHED_FILE": "Bifogad fil", "ATTACH_MAXSIZE_VALIDATE": "Filstorleken måste vara mindre än {0}", - "AUDIO_FILE_OR_URL_MSG": "Vänligen välj antingen en ljudfil eller ange en ljudfils URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Vänligen ange antingen en ljudfil eller en ljud-URL, inte båda!", "Blur": "Fläck", "Blur Radius": "Oskärpa radie", "Brush": "Borsta", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Lägre alfa", "LOWER_ROMAN": "Nedre romerska", "MAX_ATTACH_MSG": "Maximal gräns för bilaga har uppnåtts", + "MEDIA_ERROR": "Det gick inte att ladda media.", "MONTH": "Månad", "NO_RESULTS": "Inga resultat", "NUMBERED": "Numrerad", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Öppna i nytt fönster", "PICK_GIF": "Välj en gif", "PICK_IMAGE": "Välj bild", + "READ_LESS": "Läs mindre", + "READ_MORE": "Läs mer", "REDO_MSG": "Gör om det senaste kommandot", "REMOVE": "Ta bort", "RESET": "Återställ", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider Vit Svart Färg", "Square": "Fyrkant", "TAB": "FLIK", + "TABLE_CONTENT": "Klicka för att se tabellinnehåll", "TEXT_TO_DISPLAY": "Text att visa", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Titel Case", diff --git a/lib/assets/strings/th.json b/lib/assets/strings/th.json index 4d1cf2c..f162296 100644 --- a/lib/assets/strings/th.json +++ b/lib/assets/strings/th.json @@ -4,8 +4,6 @@ "ALL": "ทั้งหมด", "ATTACHED_FILE": "ไฟล์ที่แนบมา", "ATTACH_MAXSIZE_VALIDATE": "ขนาดไฟล์ต้องน้อยกว่า {0}", - "AUDIO_FILE_OR_URL_MSG": "โปรดเลือกไฟล์เสียงหรือป้อน URL ไฟล์เสียง!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "โปรดป้อนไฟล์เสียงหรือ URL เสียง ไม่ใช่ทั้งสองอย่าง!", "Blur": "เบลอ", "Blur Radius": "รัศมีการเบลอ", "Brush": "แปรง", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "อัลฟ่าตอนล่าง", "LOWER_ROMAN": "โรมันตอนล่าง", "MAX_ATTACH_MSG": "ไฟล์แนบถึงขีดจำกัดสูงสุดแล้ว", + "MEDIA_ERROR": "เกิดข้อผิดพลาดในการโหลดสื่อ", "MONTH": "เดือน", "NO_RESULTS": "ไม่มีผลลัพธ์", "NUMBERED": "หมายเลข", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "เปิดหน้าต่างใหม่", "PICK_GIF": "เลือก Gif", "PICK_IMAGE": "เลือกรูปภาพ", + "READ_LESS": "อ่านน้อยลง", + "READ_MORE": "อ่านเพิ่มเติม", "REDO_MSG": "ทำซ้ำคำสั่งสุดท้าย", "REMOVE": "เอาออก", "RESET": "รีเซ็ต", @@ -119,6 +120,7 @@ "Slider White Black Color": "สไลเดอร์ สีขาว สีดำ", "Square": "สี่เหลี่ยม", "TAB": "แท็บ", + "TABLE_CONTENT": "คลิกเพื่อดูเนื้อหาตาราง", "TEXT_TO_DISPLAY": "ข้อความที่จะแสดง", "TIMES_NEW_ROMAN": "ไทมส์นิวโรมัน", "TITLE_CASE": "กรณีชื่อเรื่อง", diff --git a/lib/assets/strings/tl.json b/lib/assets/strings/tl.json index c869c07..338f793 100644 --- a/lib/assets/strings/tl.json +++ b/lib/assets/strings/tl.json @@ -4,8 +4,6 @@ "ALL": "Lahat", "ATTACHED_FILE": "Naka-attach na file", "ATTACH_MAXSIZE_VALIDATE": "Ang laki ng file ay dapat na mas mababa sa {0}", - "AUDIO_FILE_OR_URL_MSG": "Mangyaring pumili ng audio file o maglagay ng URL ng audio file!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Mangyaring maglagay ng alinman sa isang audio file o isang audio URL, hindi pareho!", "Blur": "Malabo", "Blur Radius": "Palabuin ang Radius", "Brush": "Magsipilyo", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Mababang Alpha", "LOWER_ROMAN": "Lower Roman", "MAX_ATTACH_MSG": "Naabot na ang max na limitasyon ng attachment", + "MEDIA_ERROR": "Error sa paglo-load ng media.", "MONTH": "Buwan", "NO_RESULTS": "Walang resulta", "NUMBERED": "May bilang", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Magbukas sa bagong bintana", "PICK_GIF": "Pumili ng Gif", "PICK_IMAGE": "Pumili ng Larawan", + "READ_LESS": "Magbasa ng Mas Kaunti", + "READ_MORE": "Magbasa pa", "REDO_MSG": "Gawin muli ang huling utos", "REMOVE": "Alisin", "RESET": "I-reset", @@ -119,6 +120,7 @@ "Slider White Black Color": "Slider Puting Itim na Kulay", "Square": "Square", "TAB": "TAB", + "TABLE_CONTENT": "I-click upang makita ang nilalaman ng talahanayan", "TEXT_TO_DISPLAY": "Tekstong ipapakita", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Kaso ng Pamagat", diff --git a/lib/assets/strings/tr.json b/lib/assets/strings/tr.json index bd4a630..4966731 100644 --- a/lib/assets/strings/tr.json +++ b/lib/assets/strings/tr.json @@ -4,8 +4,6 @@ "ALL": "Herşey", "ATTACHED_FILE": "Ekli dosya", "ATTACH_MAXSIZE_VALIDATE": "Dosya boyutu {0} boyutundan küçük olmalıdır", - "AUDIO_FILE_OR_URL_MSG": "Lütfen bir ses dosyası seçin veya bir ses dosyası URL'si girin!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Lütfen bir ses dosyası veya bir ses URL'si girin, ikisini birden değil!", "Blur": "Bulanıklık", "Blur Radius": "Bulanıklık Yarıçapı", "Brush": "Fırçalamak", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alt Alfa", "LOWER_ROMAN": "Aşağı Roma", "MAX_ATTACH_MSG": "Ek maksimum sınırına ulaşıldı", + "MEDIA_ERROR": "Medya yüklenirken hata oluştu.", "MONTH": "Ay", "NO_RESULTS": "Sonuç yok", "NUMBERED": "Sayılı", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Yeni pencerede aç", "PICK_GIF": "Bir Gif Seç", "PICK_IMAGE": "Resim Seç", + "READ_LESS": "Az oku", + "READ_MORE": "Daha fazla oku", "REDO_MSG": "Son komutu yeniden yap", "REMOVE": "Kaldır", "RESET": "Sıfırla", @@ -119,6 +120,7 @@ "Slider White Black Color": "Kaydırıcı Beyaz Siyah Renk", "Square": "Kare", "TAB": "SEKME", + "TABLE_CONTENT": "Tablo içeriğini görmek için tıklayın", "TEXT_TO_DISPLAY": "Görüntülenecek metin", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Başlık Örneği", diff --git a/lib/assets/strings/uk.json b/lib/assets/strings/uk.json index 3266cc3..2609f5a 100644 --- a/lib/assets/strings/uk.json +++ b/lib/assets/strings/uk.json @@ -4,8 +4,6 @@ "ALL": "Усі", "ATTACHED_FILE": "Вкладений файл", "ATTACH_MAXSIZE_VALIDATE": "Розмір файлу має бути меншим за {0}", - "AUDIO_FILE_OR_URL_MSG": "Виберіть аудіофайл або введіть URL-адресу аудіофайлу!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Будь ласка, введіть або аудіофайл, або URL-адресу аудіо, а не обидва!", "Blur": "Розмиття", "Blur Radius": "Радіус розмиття", "Brush": "Кисть", @@ -51,7 +49,7 @@ "EDITOR_TEXT": "Текст", "ENTER": "ENTER", "ESCAPE": "Втеча", - "Emoji": "Емоджі", + "Emoji": "Емодзі", "FILE": "Файл", "FILE_COMPRESSING_ER": "Під час стиснення файлу сталася помилка", "FILE_DUPLICATE_ER": "Файл уже прикріплено. Виберіть інший файл", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Нижня Альфа", "LOWER_ROMAN": "Нижній Роман", "MAX_ATTACH_MSG": "Досягнуто максимальної кількості вкладених файлів", + "MEDIA_ERROR": "Помилка завантаження медіа.", "MONTH": "Місяць", "NO_RESULTS": "Немає результатів", "NUMBERED": "Пронумерований", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Відкрити в новому вікні", "PICK_GIF": "Виберіть Gif", "PICK_IMAGE": "Виберіть зображення", + "READ_LESS": "Читайте менше", + "READ_MORE": "Детальніше", "REDO_MSG": "Повторити останню команду", "REMOVE": "Видалити", "RESET": "Скидання", @@ -119,6 +120,7 @@ "Slider White Black Color": "Слайдер білий чорний колір", "Square": "Майдан", "TAB": "TAB", + "TABLE_CONTENT": "Натисніть, щоб переглянути вміст таблиці", "TEXT_TO_DISPLAY": "Текст для відображення", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Регістр назви", diff --git a/lib/assets/strings/vi.json b/lib/assets/strings/vi.json index 137a233..22bec32 100644 --- a/lib/assets/strings/vi.json +++ b/lib/assets/strings/vi.json @@ -4,8 +4,6 @@ "ALL": "Tất cả các", "ATTACHED_FILE": "Tập tin đính kèm", "ATTACH_MAXSIZE_VALIDATE": "Kích thước tệp phải nhỏ hơn {0}", - "AUDIO_FILE_OR_URL_MSG": "Vui lòng chọn tệp âm thanh hoặc nhập URL tệp âm thanh!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "Vui lòng nhập tệp âm thanh hoặc URL âm thanh, không phải cả hai!", "Blur": "Mơ hồ", "Blur Radius": "Bán kính mờ", "Brush": "Chải", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "Alpha thấp hơn", "LOWER_ROMAN": "Hạ La Mã", "MAX_ATTACH_MSG": "Đã đạt đến giới hạn tối đa của tệp đính kèm", + "MEDIA_ERROR": "Lỗi tải phương tiện.", "MONTH": "tháng", "NO_RESULTS": "Ko có kết quả", "NUMBERED": "đánh số", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "Mở trong cửa sổ mới", "PICK_GIF": "Chọn một Gif", "PICK_IMAGE": "Chọn hình ảnh", + "READ_LESS": "Đọc ít hơn", + "READ_MORE": "Đọc thêm", "REDO_MSG": "Làm lại lệnh cuối cùng", "REMOVE": "Tẩy", "RESET": "Cài lại", @@ -119,6 +120,7 @@ "Slider White Black Color": "Thanh trượt màu trắng đen", "Square": "Quảng trường", "TAB": "CHUYỂN HƯỚNG", + "TABLE_CONTENT": "Click để xem nội dung bảng", "TEXT_TO_DISPLAY": "Văn bản để hiển thị", "TIMES_NEW_ROMAN": "Times New Roman", "TITLE_CASE": "Trường hợp tiêu đề", diff --git a/lib/assets/strings/zh.json b/lib/assets/strings/zh.json index 4d43cf4..f8d479c 100644 --- a/lib/assets/strings/zh.json +++ b/lib/assets/strings/zh.json @@ -4,8 +4,6 @@ "ALL": "所有", "ATTACHED_FILE": "附件", "ATTACH_MAXSIZE_VALIDATE": "文件大小必须小于 {0}", - "AUDIO_FILE_OR_URL_MSG": "请选择音频文件或输入音频文件 URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "请输入音频文件或音频 URL,不能同时输入两者!", "Blur": "模糊", "Blur Radius": "模糊半径", "Brush": "刷子", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "较低的阿尔法", "LOWER_ROMAN": "下罗马语", "MAX_ATTACH_MSG": "已达到附件最大限制", + "MEDIA_ERROR": "加载媒体时出错。", "MONTH": "月", "NO_RESULTS": "没有结果", "NUMBERED": "编号", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "在新窗口中打开", "PICK_GIF": "选择一个 Gif", "PICK_IMAGE": "选择图片", + "READ_LESS": "少读", + "READ_MORE": "阅读更多", "REDO_MSG": "重做上一条命令", "REMOVE": "去掉", "RESET": "重启", @@ -119,6 +120,7 @@ "Slider White Black Color": "滑块白色黑色", "Square": "正方形", "TAB": "标签", + "TABLE_CONTENT": "点击查看表格内容", "TEXT_TO_DISPLAY": "要显示的文本", "TIMES_NEW_ROMAN": "英语字体格式一种", "TITLE_CASE": "标题大小写", diff --git a/lib/assets/strings/zh_HK.json b/lib/assets/strings/zh_HK.json index 4d43cf4..f8d479c 100644 --- a/lib/assets/strings/zh_HK.json +++ b/lib/assets/strings/zh_HK.json @@ -4,8 +4,6 @@ "ALL": "所有", "ATTACHED_FILE": "附件", "ATTACH_MAXSIZE_VALIDATE": "文件大小必须小于 {0}", - "AUDIO_FILE_OR_URL_MSG": "请选择音频文件或输入音频文件 URL!", - "AUDIO_FILE_OR_URL_MSG_NOT_BOTH": "请输入音频文件或音频 URL,不能同时输入两者!", "Blur": "模糊", "Blur Radius": "模糊半径", "Brush": "刷子", @@ -89,6 +87,7 @@ "LOWER_ALPHA": "较低的阿尔法", "LOWER_ROMAN": "下罗马语", "MAX_ATTACH_MSG": "已达到附件最大限制", + "MEDIA_ERROR": "加载媒体时出错。", "MONTH": "月", "NO_RESULTS": "没有结果", "NUMBERED": "编号", @@ -96,6 +95,8 @@ "OPEN_IN_NEW_WINDOW": "在新窗口中打开", "PICK_GIF": "选择一个 Gif", "PICK_IMAGE": "选择图片", + "READ_LESS": "少读", + "READ_MORE": "阅读更多", "REDO_MSG": "重做上一条命令", "REMOVE": "去掉", "RESET": "重启", @@ -119,6 +120,7 @@ "Slider White Black Color": "滑块白色黑色", "Square": "正方形", "TAB": "标签", + "TABLE_CONTENT": "点击查看表格内容", "TEXT_TO_DISPLAY": "要显示的文本", "TIMES_NEW_ROMAN": "英语字体格式一种", "TITLE_CASE": "标题大小写", diff --git a/lib/src/components/atoms.dart b/lib/src/components/atoms.dart index 331765a..7237525 100644 --- a/lib/src/components/atoms.dart +++ b/lib/src/components/atoms.dart @@ -3,8 +3,10 @@ export 'atoms/absorb_pointer.dart'; export 'atoms/avatar.dart'; export 'atoms/back_button.dart'; +export 'atoms/border_clipper.dart'; export 'atoms/button.dart'; export 'atoms/card.dart'; +export 'atoms/conditional_wrapper.dart'; export 'atoms/dashed_line.dart'; export 'atoms/expandable.dart'; export 'atoms/floating_action_button.dart'; @@ -19,3 +21,4 @@ export 'atoms/slidable_widget.dart'; export 'atoms/tab.dart'; export 'atoms/toggle_button.dart'; export 'atoms/unread_badge_widget.dart'; +export 'atoms/ximage.dart'; diff --git a/lib/src/components/atoms/absorb_pointer.dart b/lib/src/components/atoms/absorb_pointer.dart index d2f95bb..8f409ff 100644 --- a/lib/src/components/atoms/absorb_pointer.dart +++ b/lib/src/components/atoms/absorb_pointer.dart @@ -62,7 +62,8 @@ class ZdsAbsorbPointer extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('duration', duration)); - properties.add(DiagnosticsProperty('absorbing', absorbing)); + properties + ..add(DiagnosticsProperty('duration', duration)) + ..add(DiagnosticsProperty('absorbing', absorbing)); } } diff --git a/lib/src/components/atoms/avatar.dart b/lib/src/components/atoms/avatar.dart index 3dcd74f..961233a 100644 --- a/lib/src/components/atoms/avatar.dart +++ b/lib/src/components/atoms/avatar.dart @@ -1,6 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A circular container used to display a user's profile picture or initials. /// @@ -15,8 +15,21 @@ import '../../../zds_flutter.dart'; /// * [ZdsNetworkAvatar], an avatar that fetches the image from an URL. /// * [ZdsSelectableListTile], where [ZdsAvatar] is used as the [ZdsSelectableListTile.leading] widget. /// * [ZdsProfile], where [ZdsAvatar] can be used for [ZdsProfile.avatar]. -/// * [computeForeground], a function used to calculate the text color for any background color. class ZdsAvatar extends StatelessWidget implements PreferredSizeWidget { + /// Displays either initials or an image in an optionally tappable circular container. + /// If given both [initials] and [image], the avatar will always show [image]. + /// + /// If [size] is not null it must be greater than 0. + const ZdsAvatar({ + super.key, + this.image, + this.initials, + this.onTap, + this.size, + this.textStyle, + this.backgroundColor, + }) : assert(size != null ? size > 0 : size == null, 'Size must be greater than 0'); + /// An image that will fill the entire avatar. As the avatar is circular, a square image will not get its corners /// shown, but the original image will be intact. /// @@ -47,29 +60,16 @@ class ZdsAvatar extends StatelessWidget implements PreferredSizeWidget { /// Defaults to [ColorScheme.secondary]. final Color? backgroundColor; - /// Displays either initials or an image in an optionally tappable circular container. - /// If given both [initials] and [image], the avatar will always show [image]. - /// - /// If [size] is not null it must be greater than 0. - const ZdsAvatar({ - super.key, - this.image, - this.initials, - this.onTap, - this.size, - this.textStyle, - this.backgroundColor, - }) : assert(size != null ? size > 0 : size == null, 'Size must be greater than 0'); - @override Widget build(BuildContext context) { + final themeData = Theme.of(context); return GestureDetector( onTap: onTap, child: Container( height: size ?? preferredSize.height, width: size ?? preferredSize.width, decoration: BoxDecoration( - color: backgroundColor ?? Theme.of(context).colorScheme.secondary, + color: backgroundColor ?? themeData.colorScheme.secondary, image: image != null ? DecorationImage(image: image!.image, fit: BoxFit.cover) : null, shape: BoxShape.circle, ), @@ -78,9 +78,9 @@ class ZdsAvatar extends StatelessWidget implements PreferredSizeWidget { child: Text( initials!, style: textStyle ?? - Theme.of(context).textTheme.displaySmall!.copyWith( - color: computeForeground(backgroundColor ?? Theme.of(context).colorScheme.secondary), - ), + themeData.textTheme.displaySmall?.copyWith( + color: (backgroundColor ?? themeData.colorScheme.secondary).onColor, + ), ), ) : null, @@ -90,13 +90,15 @@ class ZdsAvatar extends StatelessWidget implements PreferredSizeWidget { @override Size get preferredSize => const Size(48, 48); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('initials', initials)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(DoubleProperty('size', size)); - properties.add(DiagnosticsProperty('textStyle', textStyle)); - properties.add(ColorProperty('backgroundColor', backgroundColor)); + properties + ..add(StringProperty('initials', initials)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(DoubleProperty('size', size)) + ..add(DiagnosticsProperty('textStyle', textStyle)) + ..add(ColorProperty('backgroundColor', backgroundColor)); } } diff --git a/lib/src/components/atoms/back_button.dart b/lib/src/components/atoms/back_button.dart index e13c042..f7d7855 100644 --- a/lib/src/components/atoms/back_button.dart +++ b/lib/src/components/atoms/back_button.dart @@ -3,18 +3,18 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A back button that will, by default, call [Navigator.maybePop] when pressed. class ZdsBackButton extends StatelessWidget { + /// A back button that will, by default, call [Navigator.maybePop] when pressed. + const ZdsBackButton({super.key, this.onPressed}); + /// The function to be called whenever the user presses this button. /// /// Calls [Navigator.maybePop] by default. final VoidCallback? onPressed; - /// A back button that will, by default, call [Navigator.maybePop] when pressed. - const ZdsBackButton({super.key, this.onPressed}); - @override Widget build(BuildContext context) { assert(debugCheckHasMaterialLocalizations(context), 'Localizations must be initialized'); diff --git a/lib/src/components/atoms/border_clipper.dart b/lib/src/components/atoms/border_clipper.dart new file mode 100644 index 0000000..9c3c624 --- /dev/null +++ b/lib/src/components/atoms/border_clipper.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; + +/// A custom clipper that allows you to clip with different offsets on each side. +/// +/// This `ZdsBorderClipper` class extends `CustomClipper` and +/// can be used to create a custom [Path] for a `ClipPath` widget with distinct border clip lengths. +/// +/// All the four sides (parameters: `top`, `bottom`, `left`, `right`) have to be provided upon creating an object. +/// These parameters represent the offsets from the corresponding sides. +/// +/// If any of the insets (parameters) change, the clipping area will be recalculated. +/// +/// # Example +/// ``` +/// ZdsBorderClipper clipper = ZdsBorderClipper( +/// top: 10, +/// bottom: 10, +/// left: 10, +/// right: 10, +/// ); +/// ClipPath( +/// clipper: clipper, +/// child: YourChildWidget(), +/// ); +/// ``` +@immutable +class ZdsBorderClipper extends CustomClipper { + /// Constructor for ZdsBorderClipper. + const ZdsBorderClipper({ + required this.top, + required this.bottom, + required this.left, + required this.right, + }); + + /// Top border clip length. + final double top; + + /// Bottom border clip length. + final double bottom; + + /// Left border clip length. + final double left; + + /// Right border clip length. + final double right; + + /// Create a new path using the parameters provided in the constructor. + @override + Path getClip(Size size) { + return Path() + ..moveTo(left, top) + ..lineTo(size.width - right, top) + ..lineTo(size.width - right, size.height - bottom) + ..lineTo(left, size.height - bottom) + ..close(); + } + + /// Reclip only if any of the inset parameters have changed. + @override + bool shouldReclip(covariant CustomClipper oldClipper) { + return oldClipper is! ZdsBorderClipper || + oldClipper.top != top || + oldClipper.bottom != bottom || + oldClipper.left != left || + oldClipper.right != right; + } +} diff --git a/lib/src/components/atoms/button.dart b/lib/src/components/atoms/button.dart index 440805c..bc84499 100644 --- a/lib/src/components/atoms/button.dart +++ b/lib/src/components/atoms/button.dart @@ -1,10 +1,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Variants of ZdsButton. -enum _ZdsButtonVariant { +enum ZdsButtonVariant { /// Filled button where the background is the defined color. filled, @@ -18,8 +18,6 @@ enum _ZdsButtonVariant { muted, } -// TODO(colors): Add Zeta. - /// An ElevatedButton with pre-applied Zds styling. /// /// There are four variants: @@ -36,64 +34,6 @@ enum _ZdsButtonVariant { /// /// The other parameters act the same way as the ones in [ElevatedButton]. class ZdsButton extends StatelessWidget { - /// The Widget that will go inside the button, typically a [Text] with style [Theme.textTheme.titleMedium]. - /// - /// Must not be null. - final Widget child; - - /// Whether to use danger/red colors. If true, the variant used must be either [ZdsButton] or [ZdsButton.outlined]. - /// - /// Defaults to false. - final bool isDangerButton; - - /// Whether to use white text as the button is on a dark background. Can only be used with [ZdsButton.text] - final bool isOnDarkBackground; - - /// Whether to autofocus on this button. - /// - /// Defaults to false. - final bool autofocus; - - /// Whether to clip the contents of this button. - /// - /// Defaults to [Clip.none] - final Clip clipBehavior; - - /// FocusNode for the button. - /// - /// The [autofocus] and [clipBehavior] arguments must not be null. - final FocusNode? focusNode; - - /// If this and [onTap] are null, the button will be disabled. - final VoidCallback? onLongPress; - - /// Called whenever a pointer enters or exits the button response area, with true if a pointer has entered this - /// button and false if it has exited it. - final ValueChanged? onHover; - - /// Called when the focus changes, with true if this widget's node gains focus, and false if it loses focus. - final ValueChanged? onFocusChange; - - /// If this and [onLongPress] are null, the button will be disabled. - final VoidCallback? onTap; - - /// padding for the text within the button - final EdgeInsets? textPadding; - - /// Custom color override. - /// - /// Changes: - /// * [ZdsButton.filled] - background color. - /// * [ZdsButton.text] - text color. - /// * [ZdsButton.outlined - outline color. - /// * [ZdsButton.muted] - no change. - final Color? customColor; - - /// This is for talkback text on child. - final String? semanticLabel; - - final _ZdsButtonVariant _variant; - /// Creates a filled ZdsButton. (Primary button). Use [ZdsButton.filled] until old buttons are fully removed. /// Currently, this acts as a backward compatible constructor for the old buttons. /// @@ -111,7 +51,7 @@ class ZdsButton extends StatelessWidget { this.onFocusChange, this.textPadding, this.semanticLabel, - }) : _variant = _ZdsButtonVariant.filled, + }) : _variant = ZdsButtonVariant.filled, isOnDarkBackground = false, customColor = null; @@ -133,7 +73,7 @@ class ZdsButton extends StatelessWidget { this.textPadding, this.customColor, this.semanticLabel, - }) : _variant = _ZdsButtonVariant.filled, + }) : _variant = ZdsButtonVariant.filled, isOnDarkBackground = false; /// Creates an outlined ZdsButton. (Secondary button) @@ -153,7 +93,7 @@ class ZdsButton extends StatelessWidget { this.textPadding, this.customColor, this.semanticLabel, - }) : _variant = _ZdsButtonVariant.outlined, + }) : _variant = ZdsButtonVariant.outlined, isOnDarkBackground = false; /// Creates a ZdsButton that behaves as a TextButton. (Tertiary button) @@ -173,7 +113,7 @@ class ZdsButton extends StatelessWidget { this.textPadding, this.customColor, this.semanticLabel, - }) : _variant = _ZdsButtonVariant.text, + }) : _variant = ZdsButtonVariant.text, isDangerButton = false; /// Constructs a muted ZdsButton. (Quaternary button) @@ -192,13 +132,71 @@ class ZdsButton extends StatelessWidget { this.textPadding, this.customColor, this.semanticLabel, - }) : _variant = _ZdsButtonVariant.muted, + }) : _variant = ZdsButtonVariant.muted, isOnDarkBackground = false, isDangerButton = false; + /// The Widget that will go inside the button, typically a [Text] with style [Theme.textTheme.titleMedium]. + /// + /// Must not be null. + final Widget child; + + /// Whether to use danger/red colors. If true, the variant used must be either [ZdsButton] or [ZdsButton.outlined]. + /// + /// Defaults to false. + final bool isDangerButton; + + /// Whether to use white text as the button is on a dark background. Can only be used with [ZdsButton.text] + final bool isOnDarkBackground; + + /// Whether to autofocus on this button. + /// + /// Defaults to false. + final bool autofocus; + + /// Whether to clip the contents of this button. + /// + /// Defaults to [Clip.none] + final Clip clipBehavior; + + /// FocusNode for the button. + /// + /// The [autofocus] and [clipBehavior] arguments must not be null. + final FocusNode? focusNode; + + /// If this and [onTap] are null, the button will be disabled. + final VoidCallback? onLongPress; + + /// Called whenever a pointer enters or exits the button response area, with true if a pointer has entered this + /// button and false if it has exited it. + final ValueChanged? onHover; + + /// Called when the focus changes, with true if this widget's node gains focus, and false if it loses focus. + final ValueChanged? onFocusChange; + + /// If this and [onLongPress] are null, the button will be disabled. + final VoidCallback? onTap; + + /// padding for the text within the button + final EdgeInsets? textPadding; + + /// Custom color override. + /// + /// Changes: + /// * [ZdsButton.filled] - background color. + /// * [ZdsButton.text] - text color. + /// * [ZdsButton.outlined] - outline color. + /// * [ZdsButton.muted] - no change. + final Color? customColor; + + /// This is for talkback text on child. + final String? semanticLabel; + + final ZdsButtonVariant _variant; + @override Widget build(BuildContext context) { - final isChildText = child is Text; + final bool isChildText = child is Text; return Semantics( label: semanticLabel ?? (isChildText ? (child as Text).data : ''), button: true, @@ -213,176 +211,141 @@ class ZdsButton extends StatelessWidget { onLongPress: onLongPress, onFocusChange: onFocusChange, onHover: onHover, - style: _getStyle(context, textPadding), + style: getStyle( + variant: _variant, + zetaColors: Zeta.of(context).colors, + textTheme: Theme.of(context).primaryTextTheme, + textPadding: textPadding, + isDangerButton: isDangerButton, + isOnDarkBackground: isOnDarkBackground, + customColor: customColor, + ), clipBehavior: clipBehavior, child: child, ), ); } - ButtonStyle _getStyle(BuildContext context, EdgeInsetsGeometry? tp) { - final textPadding = tp ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 6); + /// Returns a ButtonStyle based on the provided parameters. + /// + /// - [variant]: The style variant of the button. + /// - [zetaColors]: Colors configuration for the application/theme. + /// - [textTheme]: The text theme for the application/theme. + /// - [textPadding]: Optional padding for the button's text content. + /// - [isDangerButton]: Flag to determine if the button indicates a dangerous action. + /// - [isOnDarkBackground]: Flag to determine if the button is on a dark background. + /// - [customColor]: An optional color to override the default button color. + static ButtonStyle getStyle({ + required ZdsButtonVariant variant, + required ZetaColors zetaColors, + required TextTheme textTheme, + EdgeInsetsGeometry? textPadding, + bool isDangerButton = false, + bool isOnDarkBackground = false, + Color? customColor, + }) { + // Default text padding if none is provided. + final EdgeInsetsGeometry tp = textPadding ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 6); + + // Determine the default background color. + final Color defaultBackground = customColor ?? (isDangerButton ? zetaColors.negative : zetaColors.secondary); - const highlightBlueColor = Color(0xffB7DBFF); // TODO(colors): replace with theme color - final errorColor = Theme.of(context).colorScheme.error; - final onErrorColor = Theme.of(context).colorScheme.onError; - final defaultBackgroundColor = Theme.of(context).elevatedButtonTheme.style!.backgroundColor!.resolve({})!; - switch (_variant) { - case _ZdsButtonVariant.filled: + // Common textStyle for all variants. + final textStyle = MaterialStateProperty.all(textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500)); + + // Helper function to calculate the overlay color. + Color calculateOverlay({double opacity = 0.1, Color? background}) { + return customColor?.withOpacity(opacity) ?? (background ?? defaultBackground).withOpacity(opacity); + } + + switch (variant) { + case ZdsButtonVariant.filled: return ButtonStyle( - padding: MaterialStateProperty.all(textPadding), - textStyle: MaterialStateProperty.resolveWith( - (states) => Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500), + padding: MaterialStateProperty.all(tp), + textStyle: textStyle, + foregroundColor: materialStatePropertyResolver( + defaultValue: defaultBackground.onColor, + disabledValue: zetaColors.textDisabled, + ), + backgroundColor: materialStatePropertyResolver( + defaultValue: defaultBackground, + disabledValue: zetaColors.surfaceDisabled, ), - foregroundColor: MaterialStateProperty.resolveWith((Set states) { - return isDangerButton ? onErrorColor : computeForeground(defaultBackgroundColor); - }), - backgroundColor: MaterialStateProperty.resolveWith((Set states) { - if (customColor != null) { - return customColor!; - } - return isDangerButton - ? states.contains(MaterialState.disabled) - ? errorColor.withOpacity(0.33) - : errorColor - : states.contains(MaterialState.disabled) - ? defaultBackgroundColor.withOpacity(0.33) - : defaultBackgroundColor; - }), - overlayColor: MaterialStateProperty.resolveWith( - (Set states) { - final Color backgroundColor = isDangerButton ? errorColor : defaultBackgroundColor; - if (states.contains(MaterialState.pressed)) { - return backgroundColor.withLight(0.7, background: ZdsColors.black); - } - if (states.contains(MaterialState.hovered)) { - return backgroundColor.withLight(0.85, background: ZdsColors.black); - } - return null; // Use the component's default. - }, + overlayColor: materialStatePropertyResolver( + hoveredValue: defaultBackground.darken(5), // Slight darkening for hover + pressedValue: defaultBackground.darken(15), // More noticeable darkening for pressed state + defaultValue: Colors.transparent, + ), + side: materialStatePropertyResolver( + focusedValue: BorderSide(color: zetaColors.secondary.subtle, width: 3), + disabledValue: BorderSide(color: zetaColors.borderDisabled), ), - side: MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.focused)) { - return const BorderSide(color: highlightBlueColor, width: 3); - } - return null; - }), ); - case _ZdsButtonVariant.outlined: + case ZdsButtonVariant.outlined: return ButtonStyle( - padding: MaterialStateProperty.all(textPadding), - textStyle: MaterialStateProperty.resolveWith( - (states) => Theme.of(context).textTheme.titleMedium!.copyWith( - fontWeight: FontWeight.w500, - color: customColor, - ), + padding: MaterialStateProperty.all(tp), + textStyle: textStyle, + foregroundColor: materialStatePropertyResolver( + defaultValue: defaultBackground, + disabledValue: zetaColors.textDisabled, + ), + backgroundColor: materialStatePropertyResolver( + defaultValue: Colors.transparent, + disabledValue: zetaColors.surfaceDisabled, ), - foregroundColor: MaterialStateProperty.resolveWith((Set states) { - if (customColor != null) { - return customColor; - } - return isDangerButton - ? states.contains(MaterialState.disabled) - ? errorColor.withOpacity(0.33) - : errorColor - : states.contains(MaterialState.disabled) - ? defaultBackgroundColor.withOpacity(0.33) - : defaultBackgroundColor; - }), - backgroundColor: MaterialStateProperty.all(ZdsColors.transparent), - side: MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.focused)) { - return const BorderSide(color: highlightBlueColor, width: 3); - } - if (customColor != null) { - return BorderSide(color: customColor!); - } - return isDangerButton - ? BorderSide(color: states.contains(MaterialState.disabled) ? errorColor.withOpacity(0.33) : errorColor) - : BorderSide( - color: states.contains(MaterialState.disabled) - ? defaultBackgroundColor.withOpacity(0.33) - : defaultBackgroundColor, - ); - }), - overlayColor: MaterialStateProperty.resolveWith( - (Set states) { - final Color backgroundColor = isDangerButton ? errorColor : defaultBackgroundColor; - if (states.contains(MaterialState.pressed)) { - return backgroundColor.withOpacity(0.2); - } - if (states.contains(MaterialState.hovered)) { - return backgroundColor.withOpacity(0.1); - } - return null; // Use the component's default. - }, + overlayColor: materialStatePropertyResolver( + defaultValue: Colors.transparent, + hoveredValue: calculateOverlay(), + pressedValue: calculateOverlay(opacity: 0.2), + ), + side: materialStatePropertyResolver( + focusedValue: BorderSide(color: zetaColors.secondary.subtle, width: 3), + defaultValue: BorderSide(color: defaultBackground), + disabledValue: BorderSide(color: zetaColors.borderDisabled), ), ); - case _ZdsButtonVariant.text: + case ZdsButtonVariant.text: return ButtonStyle( - padding: MaterialStateProperty.all(textPadding), - textStyle: MaterialStateProperty.resolveWith( - (states) => Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w500), + padding: MaterialStateProperty.all(tp), + textStyle: textStyle, + foregroundColor: materialStatePropertyResolver( + defaultValue: isOnDarkBackground ? zetaColors.textInverse : defaultBackground, + disabledValue: zetaColors.textDisabled, + ), + backgroundColor: materialStatePropertyResolver( + defaultValue: Colors.transparent, ), - foregroundColor: MaterialStateProperty.resolveWith((Set states) { - final foregroundColor = isOnDarkBackground ? ZdsColors.white : defaultBackgroundColor; - if (customColor != null) { - return customColor; - } - if (states.contains(MaterialState.disabled)) { - return foregroundColor.withOpacity(0.33); - } - return foregroundColor; - }), - backgroundColor: MaterialStateProperty.all(ZdsColors.transparent), - overlayColor: MaterialStateProperty.resolveWith( - (Set states) { - final Color overlayColor = defaultBackgroundColor; - if (states.contains(MaterialState.pressed)) { - return overlayColor.withOpacity(0.2); - } - if (states.contains(MaterialState.hovered)) { - return overlayColor.withOpacity(0.1); - } - return null; // Use the component's default. - }, + overlayColor: materialStatePropertyResolver( + defaultValue: Colors.transparent, + hoveredValue: calculateOverlay(), + pressedValue: calculateOverlay(opacity: 0.2), + ), + side: materialStatePropertyResolver( + focusedValue: BorderSide(color: zetaColors.secondary.subtle, width: 3), + disabledValue: const BorderSide(color: Colors.transparent), ), - side: MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.focused)) { - return const BorderSide(color: highlightBlueColor, width: 3); - } - return null; - }), ); - case _ZdsButtonVariant.muted: + case ZdsButtonVariant.muted: return ButtonStyle( - padding: MaterialStateProperty.all(textPadding), - textStyle: MaterialStateProperty.resolveWith( - (states) => Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w500), + padding: MaterialStateProperty.all(tp), + textStyle: textStyle, + foregroundColor: materialStatePropertyResolver( + defaultValue: zetaColors.textDefault, + disabledValue: zetaColors.textDisabled, + ), + backgroundColor: materialStatePropertyResolver( + defaultValue: Colors.transparent, + disabledValue: zetaColors.surfaceDisabled, + ), + overlayColor: materialStatePropertyResolver( + defaultValue: Colors.transparent, + hoveredValue: calculateOverlay(background: zetaColors.borderDefault), + pressedValue: calculateOverlay(background: zetaColors.borderDefault, opacity: 0.2), ), - foregroundColor: MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.disabled)) { - return ZdsColors.blueGrey.withOpacity(0.33); - } - return ZdsColors.blueGrey; - }), - backgroundColor: MaterialStateProperty.all(ZdsColors.transparent), - side: MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.focused)) { - return const BorderSide(color: highlightBlueColor, width: 3); - } - return BorderSide(color: ZdsColors.lightGrey); - }), - overlayColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.pressed)) { - return ZdsColors.greySwatch(context)[200]; - } - if (states.contains(MaterialState.hovered)) { - return ZdsColors.greySwatch(context)[100]; - } - return null; // Use the component's default. - }, + side: materialStatePropertyResolver( + focusedValue: BorderSide(color: zetaColors.secondary.subtle, width: 3), + disabledValue: BorderSide(color: zetaColors.borderDisabled), + defaultValue: BorderSide(color: zetaColors.borderDefault), ), ); } @@ -391,17 +354,18 @@ class ZdsButton extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('isDangerButton', isDangerButton)); - properties.add(DiagnosticsProperty('isOnDarkBackground', isOnDarkBackground)); - properties.add(DiagnosticsProperty('autofocus', autofocus)); - properties.add(EnumProperty('clipBehavior', clipBehavior)); - properties.add(DiagnosticsProperty('focusNode', focusNode)); - properties.add(ObjectFlagProperty.has('onLongPress', onLongPress)); - properties.add(ObjectFlagProperty?>.has('onHover', onHover)); - properties.add(ObjectFlagProperty?>.has('onFocusChange', onFocusChange)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(DiagnosticsProperty('textPadding', textPadding)); - properties.add(ColorProperty('customColor', customColor)); - properties.add(StringProperty('semanticLabel', semanticLabel)); + properties + ..add(DiagnosticsProperty('isDangerButton', isDangerButton)) + ..add(DiagnosticsProperty('isOnDarkBackground', isOnDarkBackground)) + ..add(DiagnosticsProperty('autofocus', autofocus)) + ..add(EnumProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('focusNode', focusNode)) + ..add(ObjectFlagProperty.has('onLongPress', onLongPress)) + ..add(ObjectFlagProperty?>.has('onHover', onHover)) + ..add(ObjectFlagProperty?>.has('onFocusChange', onFocusChange)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(DiagnosticsProperty('textPadding', textPadding)) + ..add(ColorProperty('customColor', customColor)) + ..add(StringProperty('semanticLabel', semanticLabel)); } } diff --git a/lib/src/components/atoms/card.dart b/lib/src/components/atoms/card.dart index db33a94..3ba5713 100644 --- a/lib/src/components/atoms/card.dart +++ b/lib/src/components/atoms/card.dart @@ -1,11 +1,11 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Variants of [ZdsCard]. enum ZdsCardVariant { - /// Creates a card with a border on all edges of color [ZdsColors.greySwatch.shade600]. + /// Creates a card with a border on all edges of color [ZetaColors.borderDefault]. outlined, /// Creates a card with a box shadow around the edges with a radius of 4. @@ -47,6 +47,22 @@ enum ZdsCardVariant { /// * [ZdsCardHeader], used to create a title header in a card /// * [ZdsCardWithActions], a [ZdsCard] variant with an actions/status bar at the bottom. class ZdsCard extends StatelessWidget { + /// Creates a card to display information. + /// + /// [padding] and [variant] must not be null. + const ZdsCard({ + super.key, + this.child, + this.onTap, + this.backgroundColor, + this.gradient, + this.onTapHint, + this.padding = const EdgeInsets.symmetric(horizontal: 24, vertical: 20), + this.variant = ZdsCardVariant.elevated, + this.margin, + this.semanticLabel, + }); + /// The card's contents. /// /// Typically a [Row] or a [Column] so information is organized in a hierarchy from start to end. @@ -94,84 +110,84 @@ class ZdsCard extends StatelessWidget { /// If not null, the semantics in the card will be excluded. final String? semanticLabel; - /// Creates a card to display information. - /// - /// [padding] and [variant] must not be null. - const ZdsCard({ - super.key, - this.child, - this.onTap, - this.backgroundColor, - this.gradient, - this.onTapHint, - this.padding = const EdgeInsets.symmetric(horizontal: 24, vertical: 20), - this.variant = ZdsCardVariant.elevated, - this.margin, - this.semanticLabel, - }); - @override Widget build(BuildContext context) { - final borderRadius = (Theme.of(context).cardTheme.shape as RoundedRectangleBorder?)?.borderRadius as BorderRadius?; - final shadowColor = Theme.of(context).cardTheme.shadowColor; - final container = Container( + final zetaColors = Zeta.of(context).colors; + final themeData = Theme.of(context); + + // Regular border radius + BorderRadius borderRadius = BorderRadius.circular(kZdsCardRadius); + + // Check if the card shape is Rounded Rectangle and accordingly set its borderRadius + if (themeData.cardTheme.shape != null && themeData.cardTheme.shape is RoundedRectangleBorder) { + final cardShape = themeData.cardTheme.shape as RoundedRectangleBorder?; + if (cardShape != null && cardShape.borderRadius is BorderRadius) { + borderRadius = cardShape.borderRadius as BorderRadius; + } + } + + final shadowColor = themeData.cardTheme.shadowColor; + + final Container container = Container( clipBehavior: Clip.antiAlias, - margin: margin ?? Theme.of(context).cardTheme.margin, + margin: margin ?? themeData.cardTheme.margin, decoration: BoxDecoration( - color: backgroundColor ?? Theme.of(context).colorScheme.surface, + color: backgroundColor ?? themeData.colorScheme.surface, gradient: gradient, borderRadius: borderRadius, - border: variant == ZdsCardVariant.outlined - ? Border.all( - color: ZdsColors.greySwatch( - context, - )[Theme.of(context).colorScheme.brightness == Brightness.dark ? 1000 : 600]!, - ) - : null, - boxShadow: [ - if (shadowColor != null && variant == ZdsCardVariant.elevated) BoxShadow(color: shadowColor, blurRadius: 4), + border: variant == ZdsCardVariant.outlined ? Border.all(color: zetaColors.borderDefault) : null, + boxShadow: [ + if (shadowColor != null && variant == ZdsCardVariant.elevated) ...[ + BoxShadow(blurRadius: 1, color: shadowColor), + ], ], ), child: Material( - color: ZdsColors.transparent, + color: Colors.transparent, child: Semantics( onTapHint: onTapHint, - child: InkWell( - splashColor: ZdsColors.splashColor, - hoverColor: Colors.transparent, - onTap: onTap ?? () {}, - child: Padding( - padding: padding, - child: child, - ), + child: ZdsConditionalWrapper( + condition: onTap != null, + child: Padding(padding: padding, child: child), + wrapperBuilder: (child) { + return InkWell( + splashColor: zetaColors.surfaceSelected, + hoverColor: zetaColors.surfaceSelectedHovered, + onTap: onTap, + child: child, + ); + }, ), ), ), ); - if (semanticLabel != null) { - return Semantics( - label: semanticLabel, - onTapHint: onTapHint, - onTap: onTap, - excludeSemantics: true, - child: container, - ); - } else { - return container; - } + return ZdsConditionalWrapper( + condition: semanticLabel != null, + child: container, + wrapperBuilder: (Widget child) { + return Semantics( + label: semanticLabel, + onTapHint: onTapHint, + onTap: onTap, + excludeSemantics: true, + child: child, + ); + }, + ); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(ColorProperty('backgroundColor', backgroundColor)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(DiagnosticsProperty('gradient', gradient)); - properties.add(StringProperty('onTapHint', onTapHint)); - properties.add(DiagnosticsProperty('padding', padding)); - properties.add(EnumProperty('variant', variant)); - properties.add(DiagnosticsProperty('margin', margin)); - properties.add(StringProperty('semanticLabel', semanticLabel)); + properties + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(DiagnosticsProperty('gradient', gradient)) + ..add(StringProperty('onTapHint', onTapHint)) + ..add(DiagnosticsProperty('padding', padding)) + ..add(EnumProperty('variant', variant)) + ..add(DiagnosticsProperty('margin', margin)) + ..add(StringProperty('semanticLabel', semanticLabel)); } } diff --git a/lib/src/components/atoms/conditional_wrapper.dart b/lib/src/components/atoms/conditional_wrapper.dart new file mode 100644 index 0000000..9d3c596 --- /dev/null +++ b/lib/src/components/atoms/conditional_wrapper.dart @@ -0,0 +1,45 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// [ZdsConditionalWrapper] is a widget that conditionally wraps its [child] with a [wrapperBuilder] +/// based on the provided [condition]. +/// +/// If the [condition] is true, the [child] will be wrapped using [wrapperBuilder]. +/// If the [condition] is false, the [child] will be rendered as-is. +class ZdsConditionalWrapper extends StatelessWidget { + /// Creates an instance of [ZdsConditionalWrapper]. + /// + /// The [condition], [child], and [wrapperBuilder] arguments must not be null. + const ZdsConditionalWrapper({ + super.key, + required this.condition, + required this.child, + required this.wrapperBuilder, + }); + + /// Indicates whether to wrap the [child] with the [wrapperBuilder] or not. + final bool condition; + + /// The primary content of the widget which might be wrapped. + final Widget child; + + /// A function that returns a widget wrapping the [child]. + /// + /// This function is only invoked if [condition] is true. + final Widget Function(Widget child) wrapperBuilder; + + @override + Widget build(BuildContext context) { + /// Renders the [child] wrapped by [wrapperBuilder] if [condition] is true. + /// Otherwise, just renders the [child]. + return condition ? wrapperBuilder(child) : child; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('condition', condition)) + ..add(ObjectFlagProperty.has('wrapperBuilder', wrapperBuilder)); + } +} diff --git a/lib/src/components/atoms/dashed_line.dart b/lib/src/components/atoms/dashed_line.dart index c331810..5b04768 100644 --- a/lib/src/components/atoms/dashed_line.dart +++ b/lib/src/components/atoms/dashed_line.dart @@ -1,20 +1,10 @@ +import 'dart:ui'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; /// Corner attributes for the [ZdsDashedLine]. class ZdsDashedLineCorner { - /// Corner radius for top left corner. - final double topLeft; - - /// Corner radius for top right corner. - final double topRight; - - /// Corner radius for bottom right corner. - final double bottomRight; - - /// Corner radius for bottom left corner. - final double bottomLeft; - /// Specify the size of each rounded corner. const ZdsDashedLineCorner({ this.topLeft = 0, @@ -29,6 +19,18 @@ class ZdsDashedLineCorner { topRight = radius, bottomRight = radius, bottomLeft = radius; + + /// Corner radius for top left corner. + final double topLeft; + + /// Corner radius for top right corner. + final double topRight; + + /// Corner radius for bottom right corner. + final double bottomRight; + + /// Corner radius for bottom left corner. + final double bottomLeft; } /// A widget for creating dashed line or a container @@ -52,6 +54,24 @@ class ZdsDashedLineCorner { /// This widget can be used as dashed line or dashed container. When supplied with [height] or [child] it will be a /// Container. class ZdsDashedLine extends StatefulWidget { + /// A widget for creating dashed line or a container + /// + /// [color], [strokeWidth], [dottedLength], and [space] must not be null. + const ZdsDashedLine({ + super.key, + this.child, + this.color, + this.height, + this.width, + this.dottedLength = 5.0, + this.space = 3.0, + this.strokeWidth = 1.0, + this.corner, + }) : assert( + width != null || height != null || child != null, + 'Either width, height, or child must not be null else nothing would be rendered.', + ); + /// Dotted line color. /// /// Defaults to [ColorScheme.onSurface]. @@ -91,24 +111,6 @@ class ZdsDashedLine extends StatefulWidget { /// At this time, [width] and [height] will no longer be valid. final Widget? child; - /// A widget for creating dashed line or a container - /// - /// [color], [strokeWidth], [dottedLength], and [space] must not be null. - const ZdsDashedLine({ - super.key, - this.child, - this.color, - this.height, - this.width, - this.dottedLength = 5.0, - this.space = 3.0, - this.strokeWidth = 1.0, - this.corner, - }) : assert( - width != null || height != null || child != null, - 'Either width, height, or child must not be null else nothing would be rendered.', - ); - @override ZdsDashedLineState createState() => ZdsDashedLineState(); @override @@ -140,7 +142,7 @@ class ZdsDashedLineState extends State { if (_isEmpty(widget.width) && _isEmpty(widget.height) && widget.child == null) return const SizedBox(); if (widget.child != null) { tryToGetChildSize(); - final children = [ + final List children = [ Container( clipBehavior: widget.corner == null ? Clip.none : Clip.antiAlias, decoration: BoxDecoration( @@ -168,12 +170,12 @@ class ZdsDashedLineState extends State { /// Attempts to get the [_childWidth] and [_childHeight] of the child to be wrapped with a dashed line. void tryToGetChildSize() { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { try { - final box = _childKey.currentContext?.findRenderObject() as RenderBox?; - final tempWidth = box?.size.width ?? 0.0; - final tempHeight = box?.size.height ?? 0.0; - final needUpdate = tempWidth != _childWidth || tempHeight != _childHeight; + final RenderBox? box = _childKey.currentContext?.findRenderObject() as RenderBox?; + final double tempWidth = box?.size.width ?? 0.0; + final double tempHeight = box?.size.height ?? 0.0; + final bool needUpdate = tempWidth != _childWidth || tempHeight != _childHeight; if (needUpdate) { setState(() { _childWidth = tempWidth; @@ -215,8 +217,8 @@ class _DashedLinePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { - final isHorizontal = size.width > size.height; - final paint = Paint() + final bool isHorizontal = size.width > size.height; + final Paint paint = Paint() ..isAntiAlias = true ..color = color ..filterQuality = FilterQuality.high @@ -225,11 +227,11 @@ class _DashedLinePainter extends CustomPainter { if (!isShape) { /// line - final length = isHorizontal ? size.width : size.height; - final count = length / (dottedLength + space); + final double length = isHorizontal ? size.width : size.height; + final double count = length / (dottedLength + space); if (count < 2.0) return; - var startOffset = Offset.zero; - for (var i = 0; i < count.toInt(); i++) { + Offset startOffset = Offset.zero; + for (int i = 0; i < count.toInt(); i++) { canvas.drawLine( startOffset, startOffset.translate(isHorizontal ? dottedLength : 0, isHorizontal ? 0 : dottedLength), @@ -240,7 +242,7 @@ class _DashedLinePainter extends CustomPainter { } } else { /// shape - final path = Path() + final Path path = Path() ..addRRect( RRect.fromLTRBAndCorners( 0, @@ -254,17 +256,17 @@ class _DashedLinePainter extends CustomPainter { ), ); - final draw = buildDashPath(path, dottedLength, space); + final Path draw = buildDashPath(path, dottedLength, space); canvas.drawPath(draw, paint); } } Path buildDashPath(Path path, double dottedLength, double space) { - final r = Path(); - for (final metric in path.computeMetrics()) { - var start = 0.0; + final Path r = Path(); + for (final PathMetric metric in path.computeMetrics()) { + double start = 0; while (start < metric.length) { - final end = start + dottedLength; + final double end = start + dottedLength; r.addPath(metric.extractPath(start, end), Offset.zero); start = end + space; } diff --git a/lib/src/components/atoms/expandable.dart b/lib/src/components/atoms/expandable.dart index 6fcfe61..a24afd3 100644 --- a/lib/src/components/atoms/expandable.dart +++ b/lib/src/components/atoms/expandable.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; import '../../utils/tools/measure.dart'; const Duration _kFadeDuration = Duration(milliseconds: 200); @@ -17,6 +17,16 @@ const Duration _kFadeDuration = Duration(milliseconds: 200); /// /// * [readMore], an alternative way of making a collapsible widget. class ZdsExpandable extends StatelessWidget { + /// A widget that can be collapsed and expanded. + const ZdsExpandable({ + required this.child, + super.key, + this.collapsedButtonText = '', + this.expandedButtonText = '', + this.minHeight = 60, + this.color, + }); + /// The text to show in the button when the [child] is collapsed. final String collapsedButtonText; @@ -38,16 +48,6 @@ class ZdsExpandable extends StatelessWidget { /// Defaults to [ColorScheme.background]. final Color? color; - /// A widget that can be collapsed and expanded. - const ZdsExpandable({ - required this.child, - super.key, - this.collapsedButtonText = '', - this.expandedButtonText = '', - this.minHeight = 60, - this.color, - }); - @override Widget build(BuildContext context) { return child.readMore( @@ -70,12 +70,6 @@ class ZdsExpandable extends StatelessWidget { } class _ExpandableContainer extends StatefulWidget { - final String collapsedButtonText; - final String expandedButtonText; - final double minHeight; - final Widget child; - final Color color; - const _ExpandableContainer({ required this.collapsedButtonText, required this.expandedButtonText, @@ -83,6 +77,11 @@ class _ExpandableContainer extends StatefulWidget { required this.child, required this.color, }); + final String collapsedButtonText; + final String expandedButtonText; + final double minHeight; + final Widget child; + final Color color; @override _ExpandableContainerState createState() => _ExpandableContainerState(); @@ -102,7 +101,7 @@ class _ExpandableContainerState extends State<_ExpandableContainer> with SingleT double _textHeight = 0; Animation? _sizeAnimation; late AnimationController _controller; - final _keyText = GlobalKey(); + final GlobalKey> _keyText = GlobalKey(); @override void initState() { @@ -138,7 +137,7 @@ class _ExpandableContainerState extends State<_ExpandableContainer> with SingleT contentKey: _keyText, button: TextButton( style: TextButton.styleFrom( - foregroundColor: Theme.of(context).elevatedButtonTheme.style!.backgroundColor!.resolve({}), + foregroundColor: Theme.of(context).elevatedButtonTheme.style!.backgroundColor!.resolve({}), backgroundColor: Colors.transparent, ), onPressed: isExpanded ? collapse : expand, @@ -171,19 +170,13 @@ class _ExpandableContainerState extends State<_ExpandableContainer> with SingleT @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('isExpanded', isExpanded)); - properties.add(DoubleProperty('textHeight', textHeight)); + properties + ..add(DiagnosticsProperty('isExpanded', isExpanded)) + ..add(DoubleProperty('textHeight', textHeight)); } } class _ExpandableClip extends StatelessWidget { - final Widget child; - final Widget button; - final double height; - final bool isExpanded; - final Color color; - final Key? contentKey; - const _ExpandableClip({ required this.height, required this.button, @@ -192,11 +185,17 @@ class _ExpandableClip extends StatelessWidget { this.contentKey, this.isExpanded = false, }); + final Widget child; + final Widget button; + final double height; + final bool isExpanded; + final Color color; + final Key? contentKey; @override Widget build(BuildContext context) { return Column( - children: [ + children: [ ClipRect( child: SizedOverflowBox( // this is so that I can measure the real height @@ -214,7 +213,7 @@ class _ExpandableClip extends StatelessWidget { child: Stack( fit: StackFit.expand, clipBehavior: Clip.none, - children: [ + children: [ Positioned( top: -55, height: 55, @@ -246,9 +245,8 @@ class _ExpandableClip extends StatelessWidget { } class _FadeOpacity extends StatelessWidget { - final Color color; - const _FadeOpacity({required this.color}); + final Color color; @override Widget build(BuildContext context) { @@ -257,8 +255,8 @@ class _FadeOpacity extends StatelessWidget { gradient: LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, - stops: const [0.0, 1.0], - colors: [ + stops: const [0, 1], + colors: [ color, color.withOpacity(0), ], @@ -305,7 +303,7 @@ extension ExpandableTextExtension on Widget { }) { return MeasureSize( child: this, - builder: (context, size) { + builder: (BuildContext context, Size size) { final ComponentStrings strings = ComponentStrings.of(context); if (size.height < minHeight) { return Padding(padding: const EdgeInsets.only(bottom: 16), child: this); diff --git a/lib/src/components/atoms/floating_action_button.dart b/lib/src/components/atoms/floating_action_button.dart index 280df2a..9097ec4 100644 --- a/lib/src/components/atoms/floating_action_button.dart +++ b/lib/src/components/atoms/floating_action_button.dart @@ -14,28 +14,6 @@ enum _FloatingActionButtonType { regular, extended } /// an example of how to shrink on scroll is given in the example button.dart page. I do not recommend doing this /// alternative method as, visually speaking, the result is not optimal (might be achievable with further fine tuning). class ZdsFloatingActionButton extends StatelessWidget { - /// An icon to show in the FAB. - /// - /// If using [ZdsFloatingActionButton] this is required. - final Widget? icon; - - /// A function called whenever the user taps on the FAB. - final VoidCallback? onPressed; - - /// Text that describes what will occur when the button is pressed, displayed when the user long-presses - /// on the button or is using Talkback or VoiceOver. - /// - /// For more information, see [Semantics]. - final String? tooltip; - - final Widget? _extendedLabel; - - final double? _extendedIconLabelSpacing; - - final EdgeInsetsGeometry? _extendedPadding; - - final _FloatingActionButtonType _floatingActionButtonType; - /// Creates a circular floating action button. /// /// The [icon] argument must not be null. @@ -65,6 +43,28 @@ class ZdsFloatingActionButton extends StatelessWidget { _extendedIconLabelSpacing = extendedIconLabelSpacing, _extendedPadding = extendedPadding; + /// An icon to show in the FAB. + /// + /// If using [ZdsFloatingActionButton] this is required. + final Widget? icon; + + /// A function called whenever the user taps on the FAB. + final VoidCallback? onPressed; + + /// Text that describes what will occur when the button is pressed, displayed when the user long-presses + /// on the button or is using Talkback or VoiceOver. + /// + /// For more information, see [Semantics]. + final String? tooltip; + + final Widget? _extendedLabel; + + final double? _extendedIconLabelSpacing; + + final EdgeInsetsGeometry? _extendedPadding; + + final _FloatingActionButtonType _floatingActionButtonType; + @override Widget build(BuildContext context) { switch (_floatingActionButtonType) { diff --git a/lib/src/components/atoms/icon_text_button.dart b/lib/src/components/atoms/icon_text_button.dart index 35f9980..be53dd9 100644 --- a/lib/src/components/atoms/icon_text_button.dart +++ b/lib/src/components/atoms/icon_text_button.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A widget that creates a Large icon button with text. /// @@ -16,7 +16,18 @@ import '../../../zds_flutter.dart'; /// ), /// /// ``` -class ZdsIconTextButton extends StatelessWidget { +class ZdsIconTextButton extends StatelessWidget with Diagnosticable { + /// Constructs a [ZdsIconTextButton]. + const ZdsIconTextButton({ + required this.label, + super.key, + this.icon, + this.iconColor, + this.labelColor, + this.onTap, + this.backgroundColor, + }) : assert(label.length != 0, 'label must not be empty'); + /// The icon to be shown above the label final IconData? icon; @@ -39,45 +50,42 @@ class ZdsIconTextButton extends StatelessWidget { /// Defaults to [ColorScheme.primary] final Color? backgroundColor; - /// Constructs a [ZdsIconTextButton]. - const ZdsIconTextButton({ - required this.label, - super.key, - this.icon, - this.iconColor, - this.labelColor, - this.onTap, - this.backgroundColor, - }) : assert(label.length != 0, 'label must not be empty'); - @override Widget build(BuildContext context) { - final borderRadius = (Theme.of(context).cardTheme.shape as RoundedRectangleBorder?)?.borderRadius; + final themeData = Theme.of(context); + final zetaColors = Zeta.of(context).colors; + + final BorderRadiusGeometry? borderRadius = (themeData.cardTheme.shape as RoundedRectangleBorder?)?.borderRadius; return Container( height: 112, width: 112, decoration: BoxDecoration( borderRadius: borderRadius, - color: backgroundColor ?? Theme.of(context).colorScheme.primary, - boxShadow: [BoxShadow(blurRadius: 4, color: ZdsColors.blueGrey.withOpacity(0.1))], + color: backgroundColor ?? zetaColors.primary, + boxShadow: [ + BoxShadow(blurRadius: 4, color: zetaColors.shadow.withOpacity(0.5)), + ], ), child: Material( - color: ZdsColors.transparent, + color: Colors.transparent, child: Semantics( child: InkWell( onTap: onTap, child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(icon, size: 56, color: iconColor), + children: [ + Icon( + icon, + size: 56, + color: iconColor ?? (backgroundColor ?? zetaColors.primary).onColor, + ), const SizedBox(height: 8), Text( label, - style: Theme.of(context).textTheme.titleSmall?.copyWith( - color: - labelColor ?? computeForeground(backgroundColor ?? Theme.of(context).colorScheme.primary), - ), + style: themeData.textTheme.titleSmall?.copyWith( + color: labelColor ?? (backgroundColor ?? zetaColors.primary).onColor, + ), ), ], ), @@ -90,11 +98,12 @@ class ZdsIconTextButton extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('icon', icon)); - properties.add(ColorProperty('iconColor', iconColor)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(StringProperty('label', label)); - properties.add(ColorProperty('labelColor', labelColor)); - properties.add(ColorProperty('backgroundColor', backgroundColor)); + properties + ..add(DiagnosticsProperty('icon', icon)) + ..add(ColorProperty('iconColor', iconColor)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(StringProperty('label', label)) + ..add(ColorProperty('labelColor', labelColor)) + ..add(ColorProperty('backgroundColor', backgroundColor)); } } diff --git a/lib/src/components/atoms/index.dart b/lib/src/components/atoms/index.dart index 536e343..80683b6 100644 --- a/lib/src/components/atoms/index.dart +++ b/lib/src/components/atoms/index.dart @@ -1,7 +1,9 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; + +import '../../utils/tools/utils.dart'; +import '../molecules/tag.dart'; /// A component used to show status information, like index, order, or state, in a very small space. /// @@ -14,6 +16,11 @@ import '../../../zds_flutter.dart'; /// /// * [ZdsTag], which uses this component in its prefix. class ZdsIndex extends StatelessWidget { + /// Creates a small circle used to show status information at a glance. + /// This circle is optional to cater for when a leading icon is required, without a circle. + /// An example of this is 'Approved' with a leading check icon. + const ZdsIndex({super.key, this.child, this.color, this.useBoxDecoration = true}); + /// The background color of the circle. /// /// Defaults to [ColorScheme.primaryContainer]. @@ -29,28 +36,25 @@ class ZdsIndex extends StatelessWidget { /// If rectangular boolean is false in [ZdsTag], this defaults to true. final bool useBoxDecoration; - /// Creates a small circle used to show status information at a glance. - /// This circle is optional to cater for when a leading icon is required, without a circle. - /// An example of this is 'Approved' with a leading check icon. - const ZdsIndex({super.key, this.child, this.color, this.useBoxDecoration = true}); - @override Widget build(BuildContext context) { + final themeData = Theme.of(context); + final bgColor = color ?? themeData.colorScheme.primaryContainer; return Container( width: 20, height: 20, margin: !useBoxDecoration ? const EdgeInsets.only(left: 6) : EdgeInsets.zero, decoration: useBoxDecoration ? BoxDecoration( - color: color ?? Theme.of(context).colorScheme.primaryContainer, + color: bgColor, shape: BoxShape.circle, ) : const BoxDecoration(), child: Center( child: DefaultTextStyle( - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ZetaColors.of(context).white, - ), + style: safeTextStyle(themeData.textTheme.bodySmall).copyWith( + color: useBoxDecoration ? bgColor.onColor : themeData.colorScheme.onSurface, + ), child: child ?? const SizedBox(), ), ), diff --git a/lib/src/components/atoms/label.dart b/lib/src/components/atoms/label.dart index 1e59616..216e7ea 100644 --- a/lib/src/components/atoms/label.dart +++ b/lib/src/components/atoms/label.dart @@ -1,10 +1,14 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A label typically used to showcase status information. class ZdsLabel extends StatelessWidget { + /// Creates a label. + const ZdsLabel({super.key, this.icon, this.child, this.size = 16, this.padding = const EdgeInsets.only(right: 16)}) + : assert(size != null ? size >= 0 : size == null, 'Size must be greater than or equal to 0'); + /// The icon to be shown at the start of this component. final IconData? icon; @@ -23,29 +27,27 @@ class ZdsLabel extends StatelessWidget { /// Defaults to EdgeInsets.only(right: 16). final EdgeInsets padding; - /// Creates a label. - const ZdsLabel({super.key, this.icon, this.child, this.size = 16, this.padding = const EdgeInsets.only(right: 16)}) - : assert(size != null ? size >= 0 : size == null, 'Size must be greater than or equal to 0'); - @override Widget build(BuildContext context) { + final zetaColors = Zeta.of(context).colors; + return Padding( padding: padding, child: Row( - children: [ - if (icon != null) ...[ + children: [ + if (icon != null) ...[ Icon( icon, size: size, - color: Theme.of(context).colorScheme.secondary, + color: zetaColors.secondary.icon, ), const SizedBox(width: 4), ], if (child != null) DefaultTextStyle( - style: Theme.of(context).textTheme.titleSmall!.copyWith( - color: ZdsColors.blueGrey, - ), + style: safeTextStyle(Theme.of(context).textTheme.titleSmall).copyWith( + color: zetaColors.textSubtle, + ), child: child!, ), ], diff --git a/lib/src/components/atoms/notification.dart b/lib/src/components/atoms/notification.dart index 2814711..3e068df 100644 --- a/lib/src/components/atoms/notification.dart +++ b/lib/src/components/atoms/notification.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A component used to show a notification with read/unread message details. /// @@ -16,6 +16,18 @@ import '../../../zds_flutter.dart'; /// ``` class ZdsNotificationTile extends StatelessWidget { + /// Constructs a [ZdsNotificationTile]. + const ZdsNotificationTile({ + required this.dateLabel, + super.key, + this.content, + this.onTap, + this.isUnread = true, + this.leadingData, + this.leadingWidth = 12, + this.shrinkWrap = true, + }) : assert(dateLabel.length != 0, 'dateLabel must not be empty'); + /// The text that is header of the notification tile. /// final String dateLabel; @@ -40,25 +52,13 @@ class ZdsNotificationTile extends StatelessWidget { /// Defaults to true /// /// It will be used in [ZdsListTile]. - final bool? shrinkWrap; + final bool shrinkWrap; /// Width of leading widget. /// /// If set to null, leading widget will determine its own width. final double? leadingWidth; - /// Constructs a [ZdsNotificationTile]. - const ZdsNotificationTile({ - required this.dateLabel, - super.key, - this.content, - this.onTap, - this.isUnread = true, - this.leadingData, - this.leadingWidth = 12, - this.shrinkWrap = true, - }) : assert(dateLabel.length != 0, 'dateLabel must not be empty'); - @override Widget build(BuildContext context) { return ZdsListTile( diff --git a/lib/src/components/atoms/popover.dart b/lib/src/components/atoms/popover.dart index e1f27cb..9164ab1 100644 --- a/lib/src/components/atoms/popover.dart +++ b/lib/src/components/atoms/popover.dart @@ -2,7 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:popover/popover.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// An icon button with a popover. /// @@ -15,6 +15,34 @@ import '../../../zds_flutter.dart'; /// ), /// ``` class ZdsPopOverIconButton extends StatelessWidget { + /// Constructs an icon button with a popover. + const ZdsPopOverIconButton({ + required this.icon, + required this.popOverBuilder, + super.key, + this.onDismissed, + this.iconSize = 24.0, + this.visualDensity, + this.padding = const EdgeInsets.all(8), + this.alignment = Alignment.center, + this.splashRadius, + this.color, + this.focusColor, + this.hoverColor, + this.highlightColor, + this.splashColor, + this.disabledColor, + this.mouseCursor = SystemMouseCursors.click, + this.focusNode, + this.autofocus = false, + this.enableFeedback = true, + this.buttonConstraints, + this.popOverConstraints, + this.backgroundColor, + this.contentDyOffset = 0.0, + this.barrierLabel, + }) : assert(splashRadius == null || splashRadius > 0, 'Splash radius must be greater than 0'); + /// Icon for the icon button. final Icon icon; @@ -94,34 +122,6 @@ class ZdsPopOverIconButton extends StatelessWidget { /// Semantic label used for a dismissible barrier. final String? barrierLabel; - /// Constructs an icon button with a popover. - const ZdsPopOverIconButton({ - required this.icon, - required this.popOverBuilder, - super.key, - this.onDismissed, - this.iconSize = 24.0, - this.visualDensity, - this.padding = const EdgeInsets.all(8), - this.alignment = Alignment.center, - this.splashRadius, - this.color, - this.focusColor, - this.hoverColor, - this.highlightColor, - this.splashColor, - this.disabledColor, - this.mouseCursor = SystemMouseCursors.click, - this.focusNode, - this.autofocus = false, - this.enableFeedback = true, - this.buttonConstraints, - this.popOverConstraints, - this.backgroundColor, - this.contentDyOffset = 0.0, - this.barrierLabel, - }) : assert(splashRadius == null || splashRadius > 0, 'Splash radius must be greater than 0'); - @override Widget build(BuildContext context) { final Size size = MediaQuery.of(context).size; @@ -153,7 +153,7 @@ class ZdsPopOverIconButton extends StatelessWidget { enableFeedback: enableFeedback, constraints: buttonConstraints, onPressed: () async { - final result = await showZdsPopOver( + final dynamic result = await showZdsPopOver( context: context, backgroundColor: backgroundColor ?? Theme.of(context).colorScheme.surface, contentDyOffset: contentDyOffset, diff --git a/lib/src/components/atoms/selection_pills.dart b/lib/src/components/atoms/selection_pills.dart index 1e67450..6fb3025 100644 --- a/lib/src/components/atoms/selection_pills.dart +++ b/lib/src/components/atoms/selection_pills.dart @@ -3,7 +3,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/assets/icons.dart'; +import '../../utils/tools/modifiers.dart'; /// A text button that can be selectable and that accepts a string and isButtonSelected boolean value. /// @@ -18,6 +19,20 @@ import '../../../zds_flutter.dart'; /// /// /// ``` class ZdsSelectionPill extends StatelessWidget { + /// Constructs a circular, checkable button. + const ZdsSelectionPill({ + required this.label, + super.key, + this.selected = false, + this.onTap, + this.leadingIcon, + this.onClose, + this.padding = const EdgeInsets.all(9), + this.color, + this.selectedColor, + this.borderColor, + }); + /// The button's label. /// /// Prefer to use short strings. @@ -52,7 +67,6 @@ class ZdsSelectionPill extends StatelessWidget { final ZetaColorSwatch? color; ///Use [color] instead. Will be deprecated in future release. - /// /// Custom color to override pill background color. /// @@ -66,31 +80,30 @@ class ZdsSelectionPill extends StatelessWidget { /// Defaults to `ZdsColors.greyCoolSwatch[100]`. final Color? borderColor; - /// Constructs a circular, checkable button. - const ZdsSelectionPill({ - required this.label, - super.key, - this.selected = false, - this.onTap, - this.leadingIcon, - this.onClose, - this.padding = const EdgeInsets.all(9), - this.color, - this.selectedColor, - this.borderColor, - }); - @override Widget build(BuildContext context) { - final Color background = - color?.surface ?? selectedColor ?? Theme.of(context).colorScheme.secondary.withOpacity(0.1); - final Color disabledColor = color?.disabled ?? ZdsColors.greyWarmSwatch[100]!; - final Color border = color?.border ?? borderColor ?? ZdsColors.greyCoolSwatch[100]!; - - final Color selectedForeground = color?.icon ?? - (selectedColor != null ? computeForeground(selectedColor!) : Theme.of(context).colorScheme.secondary); - - final disabled = onTap == null; + final zetaColors = Zeta.of(context).colors; + final themeData = Theme.of(context); + final bool disabled = onTap == null; + + final Color background = disabled + ? zetaColors.surfaceDisabled + : selected + ? color?.surface ?? selectedColor?.withOpacity(0.2) ?? zetaColors.secondary.surface + : themeData.colorScheme.surface; + + final Color foreground = disabled + ? zetaColors.iconDisabled + : selected + ? color?.icon ?? selectedColor ?? zetaColors.secondary.icon + : zetaColors.iconSubtle; + + final Color border = borderColor ?? + (disabled + ? zetaColors.borderDisabled + : selected + ? color?.border ?? zetaColors.secondary.border + : zetaColors.borderDefault); return ExpandTapWidget( onTap: onTap ?? () {}, @@ -99,67 +112,54 @@ class ZdsSelectionPill extends StatelessWidget { child: Semantics( checked: selected, onTap: onTap, - child: Container( - constraints: const BoxConstraints(minWidth: 50), + child: Padding( padding: padding, - child: Material( - child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(19)), - onTap: onTap, - child: AnimatedContainer( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), - duration: const Duration(milliseconds: 200), - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(50)), - border: Border.fromBorderSide( - BorderSide( - color: selected ? border : Colors.transparent, - ), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(19)), + child: Material( + color: background, + child: InkWell( + onTap: onTap, + child: AnimatedContainer( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + duration: const Duration(milliseconds: 200), + constraints: const BoxConstraints(minWidth: 50), + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(50)), + border: Border.fromBorderSide(BorderSide(color: border)), + color: background, ), - color: disabled - ? disabledColor - : selected - ? background - : null, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (leadingIcon != null) - IconTheme( - data: IconThemeData(color: selectedForeground), - child: Row(children: [leadingIcon!, const SizedBox(width: 8)]), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (leadingIcon != null) + IconTheme( + data: IconThemeData(color: foreground), + child: leadingIcon!.paddingOnly(right: 8), + ), + Text( + label, + textAlign: TextAlign.center, + style: themeData.textTheme.bodyMedium?.copyWith( + color: disabled + ? zetaColors.textDisabled + : selected + ? color?.text ?? foreground + : themeData.colorScheme.onSurface, + fontWeight: selected && !disabled ? FontWeight.w600 : null, + ), ), - Text( - label, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: disabled - ? ZdsColors.greyWarmSwatch[1000] - : selected - ? color?.text ?? selectedForeground - : Theme.of(context).colorScheme.onSurface, - fontWeight: selected && !disabled ? FontWeight.w600 : null, - ), - ), - if (onClose != null) - Row( - children: [ - const SizedBox(width: 10), - IconButton( - constraints: const BoxConstraints(maxHeight: 24, maxWidth: 24), - onPressed: onClose, - icon: Icon( - ZdsIcons.close, - color: selected ? Theme.of(context).colorScheme.secondary : ZdsColors.blueGrey, - ), - splashRadius: 16, - iconSize: 16, - padding: EdgeInsets.zero, - ), - ], - ), - ], + if (onClose != null) + IconButton( + constraints: const BoxConstraints(maxHeight: 24, maxWidth: 24), + onPressed: onClose, + icon: Icon(ZdsIcons.close, color: foreground), + splashRadius: 16, + iconSize: 16, + padding: EdgeInsets.zero, + ).paddingOnly(left: 10), + ], + ), ), ), ), @@ -173,13 +173,14 @@ class ZdsSelectionPill extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('label', label)); - properties.add(DiagnosticsProperty('selected', selected)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(ObjectFlagProperty.has('onClose', onClose)); - properties.add(DiagnosticsProperty('padding', padding)); - properties.add(ColorProperty('selectedColor', selectedColor)); - properties.add(ColorProperty('borderColor', borderColor)); - properties.add(ColorProperty('color', color)); + properties + ..add(StringProperty('label', label)) + ..add(DiagnosticsProperty('selected', selected)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(ObjectFlagProperty.has('onClose', onClose)) + ..add(DiagnosticsProperty('padding', padding)) + ..add(ColorProperty('selectedColor', selectedColor)) + ..add(ColorProperty('borderColor', borderColor)) + ..add(ColorProperty('color', color)); } } diff --git a/lib/src/components/atoms/shake_animation.dart b/lib/src/components/atoms/shake_animation.dart index f48282c..72667ce 100644 --- a/lib/src/components/atoms/shake_animation.dart +++ b/lib/src/components/atoms/shake_animation.dart @@ -92,7 +92,7 @@ class ZdsShakeAnimation extends StatefulWidget { /// * [ZdsShakeAnimation]. class ZdsShakeAnimationState extends State with SingleTickerProviderStateMixin { /// Animation Controller to control the shake. - late final animationController = AnimationController(vsync: this, duration: widget.shakeDuration); + late final AnimationController animationController = AnimationController(vsync: this, duration: widget.shakeDuration); @override void dispose() { @@ -127,8 +127,8 @@ class ZdsShakeAnimationState extends State with SingleTickerP animation: animationController, // 3. optimization: pass the given child as an argument child: widget.child, - builder: (context, child) { - final sineValue = sin(widget.shakeCount * 2 * pi * animationController.value); + builder: (BuildContext context, Widget? child) { + final double sineValue = sin(widget.shakeCount * 2 * pi * animationController.value); return Transform.translate( // 4. apply a translation as a function of the animation value offset: Offset(sineValue * widget.shakeOffset, 0), diff --git a/lib/src/components/atoms/slidable_widget.dart b/lib/src/components/atoms/slidable_widget.dart index 7fcffab..3db7f55 100644 --- a/lib/src/components/atoms/slidable_widget.dart +++ b/lib/src/components/atoms/slidable_widget.dart @@ -1,9 +1,25 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A [ZdsSlidableWidget] with pre-applied Zds styling. This widget is used specifically in [ZdsSlidableButton] to create a SlidableButton. class ZdsSlidableWidget extends StatefulWidget { + /// Displays button on the slidable button in [ZdsSlidableButton], responsible for detecting slide gestures and animating movement. + const ZdsSlidableWidget({ + required this.child, + required this.height, + required this.handleWidth, + required this.onSlide, + this.onSlideValueCallback, + this.onTapDown, + this.onTapUp, + super.key, + this.isActive = true, + this.animate = false, + this.slidePercentageNeeded = 0.75, + this.stayCompleted = false, + }); + /// The `Widget` on which we want to detect the slide movement. final Widget child; @@ -37,22 +53,6 @@ class ZdsSlidableWidget extends StatefulWidget { /// Keeps the toggle at one end after completion. final bool stayCompleted; - /// Displays button on the slidable button in [ZdsSlidableButton], responsible for detecting slide gestures and animating movement. - const ZdsSlidableWidget({ - required this.child, - required this.height, - required this.handleWidth, - required this.onSlide, - this.onSlideValueCallback, - this.onTapDown, - this.onTapUp, - super.key, - this.isActive = true, - this.animate = false, - this.slidePercentageNeeded = 0.75, - this.stayCompleted = false, - }); - @override ZdsSlidableWidgetState createState() => ZdsSlidableWidgetState(); @override @@ -108,6 +108,28 @@ class ZdsSlidableWidgetState extends State with SingleTickerP _isComplete = false; } + /// Completes the slider + void complete() { + final trackWidth = context.size!.width; + + _controller.animateTo( + widget.handleWidth / trackWidth, + duration: const Duration(milliseconds: 200), + curve: Curves.fastOutSlowIn, + ); + if (!widget.animate) { + _controller.animateTo( + trackWidth, + duration: const Duration(milliseconds: 800), + curve: Curves.fastOutSlowIn, + ); + } else { + _isComplete = widget.stayCompleted; + + widget.onSlide(); + } + } + @override Widget build(BuildContext context) { return GestureDetector( @@ -115,7 +137,7 @@ class ZdsSlidableWidgetState extends State with SingleTickerP onTap: () { if (widget.isActive && !_isComplete) { _controller.animateTo(0.6, duration: const Duration(milliseconds: 800), curve: Curves.fastOutSlowIn); - Future.delayed(const Duration(milliseconds: 500), () { + Future.delayed(const Duration(milliseconds: 500), () { _controller.animateTo(1, duration: const Duration(milliseconds: 800), curve: Curves.fastOutSlowIn); }); } @@ -126,7 +148,7 @@ class ZdsSlidableWidgetState extends State with SingleTickerP } }, onTapUp: (_) => widget.onTapUp?.call(), - onPanStart: (details) { + onPanStart: (DragStartDetails details) { if (!_isComplete) { widget.onTapDown?.call(); setState(() { @@ -134,45 +156,30 @@ class ZdsSlidableWidgetState extends State with SingleTickerP }); } }, - onPanUpdate: (details) { + onPanUpdate: (DragUpdateDetails details) { if (widget.isActive && !_isComplete) { setState(() { _dxEndsPosition = details.localPosition.dx - widget.handleWidth; }); - final trackWidth = context.size!.width; - final slideValue = widget.handleWidth / trackWidth; - final val = 1 - (((details.localPosition.dx) / trackWidth) - slideValue / 2); - final isHandleAtEnd = val < slideValue; + final double trackWidth = context.size!.width; + final double slideValue = widget.handleWidth / trackWidth; + final double val = 1 - (((details.localPosition.dx) / trackWidth) - slideValue / 2); + final bool isHandleAtEnd = val < slideValue; _controller.value = isHandleAtEnd ? slideValue : val; widget.onSlideValueCallback?.call(_controller.value - slideValue); } }, - onPanEnd: (details) { + onPanEnd: (DragEndDetails details) { widget.onTapUp?.call(); if (widget.isActive && !_isComplete) { - final delta = _dxEndsPosition - _dxStartPosition; - final trackWidth = context.size!.width; - var deltaNeededToBeSlided = trackWidth * widget.slidePercentageNeeded; + final double delta = _dxEndsPosition - _dxStartPosition; + final double trackWidth = context.size!.width; + double deltaNeededToBeSlided = trackWidth * widget.slidePercentageNeeded; deltaNeededToBeSlided -= 80.0; if (delta > deltaNeededToBeSlided) { - _controller.animateTo( - widget.handleWidth / trackWidth, - duration: const Duration(milliseconds: 200), - curve: Curves.fastOutSlowIn, - ); - if (!widget.animate) { - _controller.animateTo( - trackWidth, - duration: const Duration(milliseconds: 800), - curve: Curves.fastOutSlowIn, - ); - } else { - _isComplete = widget.stayCompleted; - - widget.onSlide(); - } + complete(); } else { _controller.animateTo(1, duration: const Duration(milliseconds: 800), curve: Curves.fastOutSlowIn); widget.onSlideValueCallback?.call(1); diff --git a/lib/src/components/atoms/tab.dart b/lib/src/components/atoms/tab.dart index 971964a..1391785 100644 --- a/lib/src/components/atoms/tab.dart +++ b/lib/src/components/atoms/tab.dart @@ -1,40 +1,54 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; -/// A [Tab] with Zds styling. +import '../molecules/responsive_tab_bar.dart'; +import '../molecules/tab_bar.dart'; + +/// A [Tab] with Zebra styling. class ZdsTab extends StatelessWidget { + /// Creates a [ZdsResponsiveTabBar] or [ZdsTabBar] tab. At least one of [icon], [label], or [child] must not be null + const ZdsTab({super.key, this.icon, this.label, this.child, this.semanticLabel}) + : assert( + icon != null || label != null || child != null, + 'At least one of icon, label, or child must be defined.', + ), + assert(label == null || child == null, 'One of either label or child must be defined.'); + /// The icon shown in this tab. If [label] is also provided, the icon will be shown above it. - final Icon? icon; + /// + /// It is recommended the child is an [Icon], other Widget types may not work correctly. + /// + /// This component will always be constrained to a size of 24 x 24. + final Widget? icon; /// The text that will be shown in this tab. If [icon] is also provided, the text will be shown below it. - /// Must not be used at the same time than [child]. + /// Must not be used at the same time than [child] final String? label; /// A widget to display below the [icon], if any. If used, [label] must be null. final Widget? child; - /// Creates a [ZdsResponsiveTabBar] or [ZdsTabBar] tab. At least one of [icon], [label], or [child] must not be null. - const ZdsTab({super.key, this.icon, this.label, this.child}) - : assert( - icon != null || label != null || child != null, - 'At least one of icon, label, or child must be defined.', - ), - assert(label == null || child == null, 'One of either label or child must be defined.'); + /// Semantic label for tab. + final String? semanticLabel; @override Widget build(BuildContext context) { - return Tab( - icon: icon, - text: label, - iconMargin: const EdgeInsets.only(bottom: 4), - child: child, + return Semantics( + label: semanticLabel, + child: Tab( + icon: icon, + text: label, + iconMargin: const EdgeInsets.only(bottom: 4), + child: child, + ), ); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('label', label)); + properties + ..add(StringProperty('label', label)) + ..add(StringProperty('semanticLabel', semanticLabel)); } } diff --git a/lib/src/components/atoms/toggle_button.dart b/lib/src/components/atoms/toggle_button.dart index b1af8a4..62722d3 100644 --- a/lib/src/components/atoms/toggle_button.dart +++ b/lib/src/components/atoms/toggle_button.dart @@ -2,10 +2,21 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/theme.dart'; /// A large text button that can toggle between multiple values with Zds style. -class ZdsToggleButton extends StatefulWidget { +class ZdsToggleButton extends StatefulWidget with Diagnosticable { + /// Constructs a ZdsToggleButton. + const ZdsToggleButton({ + required this.values, + required this.onToggleCallback, + super.key, + this.backgroundColor, + this.initialValue = 0, + this.margin = const EdgeInsets.all(kBigTogglePadding), + this.foregroundColor, + }); + /// The name of the option that will be displayed on the toggle. /// /// It is recommended that this does not exceed 4 as the toggle would be very small. @@ -32,28 +43,19 @@ class ZdsToggleButton extends StatefulWidget { /// Defaults to EdgeInsets.all(18). final EdgeInsets margin; - /// Constructs a ZdsToggleButton. - const ZdsToggleButton({ - required this.values, - required this.onToggleCallback, - super.key, - this.backgroundColor, - this.initialValue = 0, - this.margin = const EdgeInsets.all(kBigTogglePadding), - this.foregroundColor, - }); - @override ZdsToggleButtonState createState() => ZdsToggleButtonState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IterableProperty('values', values)); - properties.add(ObjectFlagProperty>.has('onToggleCallback', onToggleCallback)); - properties.add(ColorProperty('backgroundColor', backgroundColor)); - properties.add(ColorProperty('foregroundColor', foregroundColor)); - properties.add(IntProperty('initialValue', initialValue)); - properties.add(DiagnosticsProperty('margin', margin)); + properties + ..add(IterableProperty('values', values)) + ..add(ObjectFlagProperty>.has('onToggleCallback', onToggleCallback)) + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(ColorProperty('foregroundColor', foregroundColor)) + ..add(IntProperty('initialValue', initialValue)) + ..add(DiagnosticsProperty('margin', margin)); } } @@ -84,8 +86,8 @@ class ZdsToggleButtonState extends State { @override Widget build(BuildContext context) { return LayoutBuilder( - builder: (context, constraints) { - final width = constraints.maxWidth - kBigTogglePadding * 2; + builder: (BuildContext context, BoxConstraints constraints) { + final double width = constraints.maxWidth - kBigTogglePadding * 2; return Container( margin: widget.margin, height: kBigToggleHeight, @@ -93,13 +95,11 @@ class ZdsToggleButtonState extends State { onTapDown: (TapDownDetails details) => _setSelectedValueFromGesture(details.localPosition.dx, width), onPanUpdate: (DragUpdateDetails details) => _setSelectedValueFromGesture(details.localPosition.dx, width), child: Stack( - children: [ + children: [ Container( height: kBigToggleHeight, decoration: ShapeDecoration( - color: ZdsColors.greySwatch( - context, - )[Theme.of(context).colorScheme.brightness == Brightness.dark ? 1100 : 200], + color: Zeta.of(context).colors.warm.shade30, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28))), ), ), @@ -122,9 +122,9 @@ class ZdsToggleButtonState extends State { SizedBox( height: kBigToggleHeight, child: Row( - children: List.generate( + children: List.generate( widget.values.length, - (index) => Expanded( + (int index) => Expanded( child: Center( child: AnimatedDefaultTextStyle( curve: Curves.ease, @@ -134,9 +134,7 @@ class ZdsToggleButtonState extends State { fontWeight: FontWeight.w500, color: (index == _selectedValue) ? widget.foregroundColor ?? - ZetaColors.computeForeground( - input: widget.backgroundColor ?? Theme.of(context).colorScheme.primary, - ) + (widget.backgroundColor ?? Theme.of(context).colorScheme.primary).onColor : Theme.of(context).colorScheme.onBackground, ), child: Text(widget.values[index]), diff --git a/lib/src/components/atoms/unread_badge_widget.dart b/lib/src/components/atoms/unread_badge_widget.dart index 928866a..b1d0fc6 100644 --- a/lib/src/components/atoms/unread_badge_widget.dart +++ b/lib/src/components/atoms/unread_badge_widget.dart @@ -3,7 +3,8 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; + +import '../molecules/icon_badge_widget.dart'; /// A widget that shows a badge to display how many unread notifications there are. /// @@ -11,6 +12,26 @@ import '../../../zds_flutter.dart'; /// /// * [IconWithBadge], an icon that uses [UnreadBadge]. class UnreadBadge extends StatelessWidget { + /// Displays the [unread] parameter in a red circle. + /// + /// If not null, [semanticsLabel] is read instead of the [unread] amount if given. + /// + /// [maximumDigits] represents how many digits will be shown. It must be equal or greater than 1 + /// (if [maximumDigits] is 3, any number over 999 will be shown as 999+). + /// + /// [maximumDigits] and [unread] must not be null. + const UnreadBadge({ + required this.unread, + super.key, + this.semanticsLabel, + this.maximumDigits = 3, + this.foregroundColor, + this.backgroundColor, + this.minWidth = 16, + this.minHeight = 16, + this.badgeContainerColor, + }) : assert(maximumDigits >= 1, 'Maximum digits must be greater than 1'); + /// The number to show in the badge. final int unread; @@ -49,31 +70,10 @@ class UnreadBadge extends StatelessWidget { /// This color is later used to draw a border around the count bubble. final Color? badgeContainerColor; - /// Displays the [unread] parameter in a red circle. - /// - /// If not null, [semanticsLabel] is read instead of the [unread] amount if given. - /// - /// [maximumDigits] represents how many digits will be shown. It must be equal or greater than 1 - /// (if [maximumDigits] is 3, any number over 999 will be shown as 999+). - /// - /// [maximumDigits] and [unread] must not be null. - const UnreadBadge({ - required this.unread, - super.key, - this.semanticsLabel, - this.maximumDigits = 3, - this.foregroundColor, - this.backgroundColor, - this.minWidth = 16, - this.minHeight = 16, - this.badgeContainerColor, - }) : assert(maximumDigits >= 1, 'Maximum digits must be greater than 1'); - @override Widget build(BuildContext context) { final String maximumNumber = '9' * maximumDigits; - final themeData = Theme.of(context); - + final ThemeData themeData = Theme.of(context); return Container( alignment: Alignment.center, padding: const EdgeInsets.all(2), @@ -101,11 +101,7 @@ class UnreadBadge extends StatelessWidget { : '+$maximumNumber', textScaleFactor: MediaQuery.of(context).textScaleFactor > 1.35 ? 1.35 : null, style: themeData.textTheme.bodySmall?.copyWith( - color: foregroundColor ?? - ZetaColors.computeForeground( - input: backgroundColor ?? themeData.colorScheme.error, - ), - // TODO(colors): determine why onError doesnt work in darkmode themeData.colorScheme.onError, + color: foregroundColor ?? (backgroundColor ?? themeData.colorScheme.error).onColor, fontSize: max(themeData.textTheme.bodySmall?.fontSize ?? 0, minHeight * 0.65), ), ), diff --git a/lib/src/components/molecules/block_table.dart b/lib/src/components/molecules/block_table.dart index 78a1996..bb28775 100644 --- a/lib/src/components/molecules/block_table.dart +++ b/lib/src/components/molecules/block_table.dart @@ -1,27 +1,33 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:linked_scroll_controller/linked_scroll_controller.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Defines a header for a [ZdsBlockTable] class ZdsBlockTableHeader { - /// The text displayed on the header - final String text; - - /// The color of the text - final Color? textColor; - /// Creates a new [ZdsBlockTableHeader] ZdsBlockTableHeader({ required this.text, this.textColor, }); + + /// The text displayed on the header + final String text; + + /// The color of the text + final Color? textColor; } /// Defines a row in a [ZdsBlockTable] class ZdsBlockTableRow { + /// Creates a new [ZdsBlockTableRow] + ZdsBlockTableRow({ + required this.data, + required this.titleCell, + this.header, + }); + /// The header text displayed above the row final String? header; @@ -30,17 +36,21 @@ class ZdsBlockTableRow { /// The data displayed in the table final List data; - - /// Creates a new [ZdsBlockTableRow] - ZdsBlockTableRow({ - required this.data, - required this.titleCell, - this.header, - }); } /// Defines a cell in a [ZdsBlockTable] class ZdsBlockTableCellData { + /// Creates a new [ZdsBlockTableCellData] + ZdsBlockTableCellData({ + this.text, + this.child, + this.textColor, + this.backgroundColor, + this.textStyle, + this.isSelected, + this.onTap, + }); + /// The child of the cell. Cannot be set if [text] is defined final Widget? child; @@ -61,21 +71,21 @@ class ZdsBlockTableCellData { /// If set to true, gives the cell a highlight background and border bool? isSelected; - - /// Creates a new [ZdsBlockTableCellData] - ZdsBlockTableCellData({ - this.text, - this.child, - this.textColor, - this.backgroundColor, - this.textStyle, - this.isSelected, - this.onTap, - }); } /// A scrollable table with floating headers class ZdsBlockTable extends StatefulWidget { + /// Creates a new [ZdsBlockTable] + const ZdsBlockTable({ + required this.headers, + required this.rows, + this.columnWidth = 80, + this.cellHeight = 34, + this.cellPadding = 18, + this.rowHeaderHeight = 24, + super.key, + }); + /// The table headers final List headers; @@ -94,28 +104,19 @@ class ZdsBlockTable extends StatefulWidget { /// The multiple for height of row header final double rowHeaderHeight; - /// Creates a new [ZdsBlockTable] - const ZdsBlockTable({ - required this.headers, - required this.rows, - this.columnWidth = 80, - this.cellHeight = 34, - this.cellPadding = 18, - this.rowHeaderHeight = 24, - super.key, - }); - @override State createState() => _BlockTable(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IterableProperty('headers', headers)); - properties.add(IterableProperty('rows', rows)); - properties.add(DoubleProperty('columnWidth', columnWidth)); - properties.add(DoubleProperty('cellHeight', cellHeight)); - properties.add(DoubleProperty('cellPadding', cellPadding)); - properties.add(DoubleProperty('rowHeaderHeight', rowHeaderHeight)); + properties + ..add(IterableProperty('headers', headers)) + ..add(IterableProperty('rows', rows)) + ..add(DoubleProperty('columnWidth', columnWidth)) + ..add(DoubleProperty('cellHeight', cellHeight)) + ..add(DoubleProperty('cellPadding', cellPadding)) + ..add(DoubleProperty('rowHeaderHeight', rowHeaderHeight)); } } @@ -127,9 +128,9 @@ class _BlockTable extends State with WidgetsBindingObserver { late ScrollController _tableBody; Widget zeroCellWidget = const SizedBox(); - List headerCellsWidgets = []; - List firstColumnCellsWidgets = []; - List bodyCellsWidgets = []; + List headerCellsWidgets = []; + List firstColumnCellsWidgets = []; + List bodyCellsWidgets = []; @override void initState() { @@ -137,7 +138,7 @@ class _BlockTable extends State with WidgetsBindingObserver { _tableHeader = _controllers.addAndGet(); _tableBody = _controllers.addAndGet(); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { headerHeight = widget.rowHeaderHeight * MediaQuery.of(context).textScaleFactor; buildTable(); }); @@ -147,7 +148,7 @@ class _BlockTable extends State with WidgetsBindingObserver { @override void didChangeMetrics() { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { buildTable(); }); } @@ -165,14 +166,14 @@ class _BlockTable extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { return ColoredBox( - color: ZdsColors.lightGrey, + color: Zeta.of(context).colors.borderSubtle, child: IntrinsicHeight( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ zeroCellWidget, Flexible( flex: 3, @@ -220,51 +221,56 @@ class _BlockTable extends State with WidgetsBindingObserver { } List _buildHeaderCells(List items) { - return List.generate( + return List.generate( items.length, - (index) => Row( - children: [ - Container( - alignment: Alignment.center, - width: _getDayColumnWidth(), - height: 28 * MediaQuery.of(context).textScaleFactor, - color: Theme.of(context).colorScheme.surface, - child: Text( - items[index].text, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: items[index].textColor, - ), + (int index) { + final themeData = Theme.of(context); + return Row( + children: [ + Container( + alignment: Alignment.center, + width: _getDayColumnWidth(), + height: 28 * MediaQuery.of(context).textScaleFactor, + color: themeData.colorScheme.surface, + child: Text( + items[index].text, + style: themeData.textTheme.bodySmall?.copyWith( + color: items[index].textColor, + ), + ), ), - ), - const SizedBox( - width: 1, - ), - ], - ), + const SizedBox( + width: 1, + ), + ], + ); + }, growable: false, ); } List _buildFirstColumnCells(List rows) { - return List.generate( + return List.generate( rows.length, - (index) { - final row = rows[index]; - final cellItem = row.titleCell; + (int index) { + final ZdsBlockTableRow row = rows[index]; + final ZdsBlockTableCellData cellItem = row.titleCell; + final themeData = Theme.of(context); + return Row( - children: [ + children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ if (row.header != null) Container( height: headerHeight, width: _getAssocColumnWidth(), decoration: BoxDecoration( - color: ZetaColors.of(context).warm.shade10, + color: Zeta.of(context).colors.borderDisabled, border: Border( bottom: BorderSide( - color: ZdsColors.lightGrey, + color: Zeta.of(context).colors.borderSubtle, ), ), ), @@ -275,7 +281,7 @@ class _BlockTable extends State with WidgetsBindingObserver { row.header!, maxLines: 2, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.bodyMedium, + style: themeData.textTheme.bodyMedium, ), ), ), @@ -283,17 +289,17 @@ class _BlockTable extends State with WidgetsBindingObserver { alignment: Alignment.center, width: _getAssocColumnWidth(), height: widget.cellHeight + widget.cellPadding, - color: cellItem.backgroundColor ?? Theme.of(context).colorScheme.surface, + color: cellItem.backgroundColor ?? themeData.colorScheme.surface, margin: const EdgeInsets.only(bottom: 1), child: cellItem.child ?? Text( cellItem.text ?? '', style: cellItem.textStyle ?? - Theme.of(context).textTheme.bodySmall?.copyWith( - fontSize: 12, - fontWeight: FontWeight.w400, - color: cellItem.textColor ?? Theme.of(context).colorScheme.onSurface, - ), + themeData.textTheme.bodySmall?.copyWith( + fontSize: 12, + fontWeight: FontWeight.w400, + color: cellItem.textColor ?? themeData.colorScheme.onSurface, + ), ).paddingOnly(left: 8), ), ], @@ -309,40 +315,38 @@ class _BlockTable extends State with WidgetsBindingObserver { } List _buildRowElements(int index) { - final List cells = []; + final List cells = []; final List rows = widget.rows; final double cellHeight = widget.cellHeight + widget.cellPadding; for (int j = 0; j < rows[index].data.length; j++) { - final List columnWidgets = []; + final List columnWidgets = []; if (rows[index].header != null) { columnWidgets.add( Container( height: headerHeight, decoration: BoxDecoration( - color: ZetaColors.of(context).warm.shade10, + color: Zeta.of(context).colors.borderDisabled, border: Border( - bottom: BorderSide(color: ZdsColors.lightGrey), + bottom: BorderSide(color: Zeta.of(context).colors.borderSubtle), ), ), ), ); } - final tableCell = rows[index].data[j]; - final isSelected = tableCell.isSelected != null && tableCell.isSelected!; + final ZdsBlockTableCellData tableCell = rows[index].data[j]; + final bool isSelected = tableCell.isSelected != null && tableCell.isSelected!; + final themeData = Theme.of(context); columnWidgets.add( Expanded( child: DecoratedBox( decoration: BoxDecoration( - border: isSelected ? Border.all(color: Theme.of(context).colorScheme.secondary, width: 2) : null, + border: isSelected ? Border.all(color: themeData.colorScheme.secondary, width: 2) : null, color: isSelected - ? Theme.of(context) - .colorScheme - .secondary - .withLight(0.1, background: Theme.of(context).colorScheme.background) - : tableCell.backgroundColor ?? Theme.of(context).colorScheme.surface, + ? themeData.colorScheme.secondary.withLight(0.1, background: themeData.colorScheme.background) + : tableCell.backgroundColor ?? themeData.colorScheme.surface, ), child: Align( child: tableCell.child ?? @@ -350,11 +354,11 @@ class _BlockTable extends State with WidgetsBindingObserver { tableCell.text!, textAlign: TextAlign.center, style: tableCell.textStyle ?? - Theme.of(context).textTheme.bodySmall?.copyWith( - fontSize: 12, - fontWeight: FontWeight.w400, - color: tableCell.textColor ?? Theme.of(context).colorScheme.onSurface, - ), + themeData.textTheme.bodySmall?.copyWith( + fontSize: 12, + fontWeight: FontWeight.w400, + color: tableCell.textColor ?? themeData.colorScheme.onSurface, + ), ), ), ), @@ -377,10 +381,10 @@ class _BlockTable extends State with WidgetsBindingObserver { cells.add(cell); } - return List.generate( + return List.generate( cells.length, - (indx) => Row( - children: [ + (int indx) => Row( + children: [ Container( alignment: Alignment.center, width: _getDayColumnWidth(), @@ -397,9 +401,9 @@ class _BlockTable extends State with WidgetsBindingObserver { } List _buildBodyRows() { - return List.generate( + return List.generate( widget.rows.length, - (index) { + (int index) { return Row( children: _buildRowElements(index), ).paddingOnly(bottom: 1); diff --git a/lib/src/components/molecules/bottom_sheet.dart b/lib/src/components/molecules/bottom_sheet.dart index 9651400..423cfca 100644 --- a/lib/src/components/molecules/bottom_sheet.dart +++ b/lib/src/components/molecules/bottom_sheet.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/semantics.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Use [showZdsBottomSheet] to display any bottom sheets instead of using this widget directly. /// @@ -13,6 +13,20 @@ import '../../../zds_flutter.dart'; /// /// * [showZdsBottomSheet], which uses this widget for its contents and is the recommended way to show bottom sheets class ZdsBottomSheet extends StatelessWidget { + /// Defines the contents of the bottom sheet. It's recommended to not use this widget directly and instead call + /// [showZdsBottomSheet] + /// + /// [child] must not be null. + const ZdsBottomSheet({ + required this.child, + super.key, + this.header, + this.bottom, + this.backgroundColor, + this.maxHeight, + this.bottomInset, + }) : assert(maxHeight != null ? maxHeight > 0 : maxHeight == null, 'Max height must be greater than 0'); + /// The widget that contains the main content of this bottom sheet. If [header] and [bottom] are not null, it will be /// shown between those two widgets final Widget child; @@ -39,30 +53,17 @@ class ZdsBottomSheet extends StatelessWidget { /// Defaults to `MediaQuery.viewPadding.bottom` final double? bottomInset; - /// Defines the contents of the bottom sheet. It's recommended to not use this widget directly and instead call - /// [showZdsBottomSheet] - /// - /// [child] must not be null. - const ZdsBottomSheet({ - required this.child, - super.key, - this.header, - this.bottom, - this.backgroundColor, - this.maxHeight, - this.bottomInset, - }) : assert(maxHeight != null ? maxHeight > 0 : maxHeight == null, 'Max height must be greater than 0'); - @override Widget build(BuildContext context) { - final colorScheme = Theme.of(context).colorScheme; - final sheetBackgroundColor = backgroundColor ?? colorScheme.background; - final headerColor = header != null ? colorScheme.surface : sheetBackgroundColor; - final headerWidget = _BottomSheetHeader(bottom: header, backgroundColor: headerColor); - final media = MediaQuery.of(context); - final maxScreenHeight = media.size.height - media.viewPadding.top; - final height = maxHeight != null && (maxHeight! > 0 && maxHeight! < maxScreenHeight) ? maxHeight! : maxScreenHeight; - final setBottomInset = bottomInset ?? MediaQuery.of(context).viewPadding.bottom; + final ColorScheme colorScheme = Theme.of(context).colorScheme; + final Color sheetBackgroundColor = backgroundColor ?? colorScheme.background; + final Color headerColor = header != null ? colorScheme.surface : sheetBackgroundColor; + final _BottomSheetHeader headerWidget = _BottomSheetHeader(bottom: header, backgroundColor: headerColor); + final MediaQueryData media = MediaQuery.of(context); + final double maxScreenHeight = media.size.height - media.viewPadding.top; + final double height = + maxHeight != null && (maxHeight! > 0 && maxHeight! < maxScreenHeight) ? maxHeight! : maxScreenHeight; + final double setBottomInset = bottomInset ?? MediaQuery.of(context).viewPadding.bottom; return MediaQuery.removePadding( removeTop: true, @@ -71,7 +72,7 @@ class ZdsBottomSheet extends StatelessWidget { constraints: BoxConstraints(maxHeight: height), color: sheetBackgroundColor, child: Stack( - children: [ + children: [ Padding( padding: EdgeInsets.only( top: headerWidget.preferredSize.height, @@ -103,9 +104,10 @@ class ZdsBottomSheet extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(ColorProperty('backgroundColor', backgroundColor)); - properties.add(DoubleProperty('maxHeight', maxHeight)); - properties.add(DoubleProperty('bottomInset', bottomInset)); + properties + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(DoubleProperty('maxHeight', maxHeight)) + ..add(DoubleProperty('bottomInset', bottomInset)); } } @@ -133,9 +135,9 @@ List buildSheetBars({ bool showClose = false, }) { final bool isTablet = context.isTablet(); - final offset = isTablet ? 0 : MediaQuery.of(context).viewPadding.bottom; + final num offset = isTablet ? 0 : MediaQuery.of(context).viewPadding.bottom; - return [ + return [ ZdsSheetHeader( headerText: title!, leading: isTablet && secondaryActionText.isNotEmpty @@ -162,14 +164,14 @@ List buildSheetBars({ ZdsBottomBar( minHeight: kBottomBarHeight + offset, child: Row( - children: [ - if (isTablet) ...[ + children: [ + if (isTablet) ...[ if (ternaryActionText.isNotEmpty) ZdsButton.text( onTap: ternaryActionOnTap, child: Text(ternaryActionText), ), - ] else ...[ + ] else ...[ if (ternaryActionText.isNotEmpty) ZdsButton.text( onTap: ternaryActionOnTap, @@ -239,7 +241,7 @@ Future showZdsBottomSheet({ required BuildContext context, required WidgetBuilder builder, Color? backgroundColor, - Color? barrierColor = ZdsColors.barrierColor, + Color? barrierColor = Colors.black54, double? maxHeight, double? maxWidth, double? bottomInset, @@ -263,10 +265,10 @@ Future showZdsBottomSheet({ shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(15)), ), - builder: (context) { - final header = headerBuilder?.call(context); - final bottom = bottomBuilder?.call(context); - final child = builder.call(context); + builder: (BuildContext context) { + final PreferredSizeWidget? header = headerBuilder?.call(context); + final PreferredSizeWidget? bottom = bottomBuilder?.call(context); + final Widget child = builder.call(context); return ZdsBottomSheet( header: header, @@ -283,9 +285,9 @@ Future showZdsBottomSheet({ barrierColor: barrierColor, barrierDismissible: isDismissible, useRootNavigator: useRootNavigator, - builder: (context) { - final header = headerBuilder?.call(context); - final bottom = bottomBuilder?.call(context); + builder: (BuildContext context) { + final PreferredSizeWidget? header = headerBuilder?.call(context); + final PreferredSizeWidget? bottom = bottomBuilder?.call(context); Widget child = builder.call(context); if (contentPadding != null) { @@ -295,7 +297,7 @@ Future showZdsBottomSheet({ ); } - final shortestSide = MediaQuery.of(context).size.shortestSide; + final double shortestSide = MediaQuery.of(context).size.shortestSide; return Dialog( backgroundColor: backgroundColor, @@ -308,7 +310,7 @@ Future showZdsBottomSheet({ width: maxWidth ?? (shortestSide * 0.75), height: maxHeight ?? (shortestSide * 0.70), child: Column( - children: [ + children: [ if (header != null) header, Expanded( child: child, @@ -324,20 +326,21 @@ Future showZdsBottomSheet({ } class _BottomSheetHeader extends StatelessWidget implements PreferredSizeWidget { + const _BottomSheetHeader({this.bottom, this.backgroundColor}); + final PreferredSizeWidget? bottom; final Color? backgroundColor; - - const _BottomSheetHeader({this.bottom, this.backgroundColor}); - static const _dragAreaHeight = 20.0; + static const double _dragAreaHeight = 20; @override Widget build(BuildContext context) { + final zetaColors = Zeta.of(context).colors; return DecoratedBox( decoration: BoxDecoration( - border: bottom != null ? Border(bottom: BorderSide(color: ZdsColors.lightGrey.withOpacity(0.5))) : null, + border: bottom != null ? Border(bottom: BorderSide(color: zetaColors.shadow)) : null, ), child: Column( - children: [ + children: [ Container( width: double.infinity, height: _dragAreaHeight, @@ -347,7 +350,7 @@ class _BottomSheetHeader extends StatelessWidget implements PreferredSizeWidget width: 120, height: 4, decoration: BoxDecoration( - color: ZdsColors.lightGrey, + color: zetaColors.borderSubtle, borderRadius: BorderRadius.circular(19), ), ), @@ -362,6 +365,7 @@ class _BottomSheetHeader extends StatelessWidget implements PreferredSizeWidget Size get preferredSize => Size.fromHeight( _dragAreaHeight + (bottom?.preferredSize.height ?? 0) + kHeaderBoarderSize, ); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); diff --git a/lib/src/components/molecules/card_actions.dart b/lib/src/components/molecules/card_actions.dart index 063d7b9..aa52782 100644 --- a/lib/src/components/molecules/card_actions.dart +++ b/lib/src/components/molecules/card_actions.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A widget used to show actions at the bottom of a [ZdsCard]. /// It's recommended to use [ZdsCardWithActions] instead of using this widget directly. @@ -10,6 +10,13 @@ import '../../../zds_flutter.dart'; /// /// * [ZdsCardWithActions], which uses this widget to show actions at the bottom of the card. class ZdsCardActions extends StatelessWidget { + /// Constructs a [ZdsCardActions]. + const ZdsCardActions({ + super.key, + this.children, + this.alignment = MainAxisAlignment.end, + }); + /// The widgets that will be laid out in a [Row]. /// /// Typically [ZdsTag] and [ZdsLabel]. @@ -21,23 +28,16 @@ class ZdsCardActions extends StatelessWidget { /// Defaults to [MainAxisAlignment.end]. final MainAxisAlignment alignment; - /// Constructs a [ZdsCardActions]. - const ZdsCardActions({ - super.key, - this.children, - this.alignment = MainAxisAlignment.end, - }); - @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 14), decoration: BoxDecoration( - border: Border(top: BorderSide(color: ZdsColors.lightGrey.withOpacity(0.5))), + border: Border(top: BorderSide(color: Zeta.of(context).colors.borderDisabled)), ), child: Row( mainAxisAlignment: alignment, - children: children ?? [], + children: children ?? [], ), ); } @@ -86,6 +86,15 @@ enum ZdsCardDirection { /// * [ZdsCardHeader], used to create a title in cards. /// * [ZdsCardActions], the widget used to lay out actions. class ZdsCardWithActions extends StatelessWidget { + /// Creates a card with a bottom section to display status/action information. + const ZdsCardWithActions({ + super.key, + this.actions, + this.children, + this.direction = ZdsCardDirection.horizontal, + this.onTap, + }); + /// Function called whenever the user taps anywhere on the card. final VoidCallback? onTap; @@ -98,30 +107,21 @@ class ZdsCardWithActions extends StatelessWidget { /// The widgets to show in the bottom part of the card. Typically contains [ZdsTag] and [ZdsLabel]. final List? actions; - /// Creates a card with a bottom section to display status/action information. - const ZdsCardWithActions({ - super.key, - this.actions, - this.children, - this.direction = ZdsCardDirection.horizontal, - this.onTap, - }); - @override Widget build(BuildContext context) { final Widget content = direction == ZdsCardDirection.horizontal ? Row( crossAxisAlignment: CrossAxisAlignment.start, - children: children?.divide(const SizedBox(width: 16)).toList() ?? [], + children: children?.divide(const SizedBox(width: 16)).toList() ?? [], ) : Column( - children: children?.divide(const SizedBox(height: 16)).toList() ?? [], + children: children?.divide(const SizedBox(height: 16)).toList() ?? [], ); return ZdsCard( padding: EdgeInsets.zero, onTap: onTap, child: Column( - children: [ + children: [ Padding( padding: const EdgeInsets.all(16).copyWith(top: 20), child: content, @@ -135,7 +135,8 @@ class ZdsCardWithActions extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(EnumProperty('direction', direction)); + properties + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(EnumProperty('direction', direction)); } } diff --git a/lib/src/components/molecules/card_header.dart b/lib/src/components/molecules/card_header.dart index 0f55194..db7553f 100644 --- a/lib/src/components/molecules/card_header.dart +++ b/lib/src/components/molecules/card_header.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A widget used to create header in a [ZdsCard]. /// @@ -12,6 +12,16 @@ import '../../../zds_flutter.dart'; /// * [ZdsCard] where this widget is typically used. /// * [ZdsCardWithActions], a [ZdsCard] variant with a bottom status/information bar. class ZdsCardHeader extends StatelessWidget { + /// Creates a card header. + /// + /// [child] can't be null. + const ZdsCardHeader({ + required this.child, + super.key, + this.leading, + this.trailing, + }); + /// An optional widget that will be placed before [child]. /// /// Typically an [Icon]. @@ -27,27 +37,17 @@ class ZdsCardHeader extends StatelessWidget { /// Typically a [Text]. If [leading] and [trailing] are not null, this widget will be set between them. final Widget child; - /// Creates a card header. - /// - /// [child] can't be null. - const ZdsCardHeader({ - required this.child, - super.key, - this.leading, - this.trailing, - }); - @override Widget build(BuildContext context) { return Stack( - children: [ + children: [ Padding( padding: const EdgeInsets.only(left: 16, top: 20, bottom: 8), child: Row( - children: [ - ...[ + children: [ + ...[ if (leading != null) leading!, - child.textStyle(Theme.of(context).textTheme.titleLarge), + child.textStyle(Theme.of(context).textTheme.headlineMedium), ].divide(const SizedBox(width: 8)), const Spacer(), ], diff --git a/lib/src/components/molecules/check_button.dart b/lib/src/components/molecules/check_button.dart index 057aec4..9bfc0a9 100644 --- a/lib/src/components/molecules/check_button.dart +++ b/lib/src/components/molecules/check_button.dart @@ -2,10 +2,22 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/theme.dart'; /// A circular button that can be checked and that accepts either a string or an icon as a child. class ZdsCheckableButton extends StatelessWidget { + /// Constructs a circular, checkable button. + const ZdsCheckableButton({ + super.key, + this.icon, + this.label, + this.isChecked = false, + this.onChanged, + }) : assert( + icon != null && label == null || icon == null && label != null, + 'Icon and label cannot be used at the same time, either of them must be null', + ); + /// The widget that will be shown inside the button. /// /// If this parameter is not null, [label] must be null. @@ -30,57 +42,63 @@ class ZdsCheckableButton extends StatelessWidget { /// Typically used to setState on [isChecked]. final VoidCallback? onChanged; - /// Constructs a circular, checkable button. - const ZdsCheckableButton({ - super.key, - this.icon, - this.label, - this.isChecked = false, - this.onChanged, - }) : assert( - icon != null && label == null || icon == null && label != null, - 'Icon and label cannot be used at the same time, either of them must be null', - ); - @override Widget build(BuildContext context) { - final ZetaColors colors = ZetaColors.of(context); + final zetaColors = Zeta.of(context).colors; + final themeData = Theme.of(context); final bool enabled = onChanged != null; - final Color foreground = - isChecked ? ZetaColors.computeForeground(input: Theme.of(context).colorScheme.secondary) : colors.warm.shade60; + + final Color foreground = isChecked + ? themeData.colorScheme.secondary.onColor + : enabled + ? zetaColors.iconSubtle + : zetaColors.iconDisabled; + + final Color background = !enabled && isChecked + ? zetaColors.secondary.subtle + : isChecked + ? zetaColors.secondary + : enabled + ? zetaColors.surfacePrimary + : zetaColors.surfaceDisabled; + + final Color borderColor = isChecked + ? zetaColors.secondary + : enabled + ? zetaColors.borderDefault + : zetaColors.borderDisabled; + return MergeSemantics( child: Semantics( checked: isChecked, enabled: enabled, - child: Material( - child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(checkableButtonSize)), - onTap: onChanged, - // SizedBox declaring the dimension instead of the container allows the Text to overflow correctly - // instead of just being clipped - child: SizedBox.square( - dimension: checkableButtonSize, - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - alignment: Alignment.center, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: enabled && !isChecked ? Border.fromBorderSide(BorderSide(color: colors.warm.shade50)) : null, - color: isChecked - ? Theme.of(context).colorScheme.secondary.withOpacity(enabled ? 1.0 : 0.5) - : enabled - ? null - : Theme.of(context).colorScheme.background, + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(kZdsCheckableButtonSize)), + child: Material( + child: InkWell( + onTap: onChanged, + // SizedBox declaring the dimension instead of the container allows the Text to overflow correctly + // instead of just being clipped + child: SizedBox.square( + dimension: kZdsCheckableButtonSize, + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: enabled && !isChecked ? Border.fromBorderSide(BorderSide(color: borderColor)) : null, + color: background, + ), + child: icon != null + ? Icon(icon, color: foreground) + : Text( + label ?? '', + overflow: TextOverflow.ellipsis, + style: themeData.textTheme.bodySmall?.copyWith( + color: foreground, + ), + ), ), - child: icon != null - ? Icon(icon, color: foreground) - : Text( - label ?? '', - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: foreground, - ), - ), ), ), ), diff --git a/lib/src/components/molecules/date_range_picker.dart b/lib/src/components/molecules/date_range_picker.dart index 16c208b..ce0db05 100644 --- a/lib/src/components/molecules/date_range_picker.dart +++ b/lib/src/components/molecules/date_range_picker.dart @@ -13,6 +13,15 @@ import 'package:flutter/services.dart'; import '../../../zds_flutter.dart'; +const Size _calendarPortraitDialogSize = Size(330, 518); +const Size _calendarLandscapeDialogSize = Size(496, 346); +const Size _inputPortraitDialogSize = Size(330, 270); +const Size _inputLandscapeDialogSize = Size(496, 160); +const Size _inputRangeLandscapeDialogSize = Size(496, 164); +const Duration _dialogSizeAnimationDuration = Duration(milliseconds: 200); +const double _inputFormPortraitHeight = 98; +const double _inputFormLandscapeHeight = 108; + /// A Material-style date picker dialog. /// /// It is used internally by [showDatePicker] or can be directly pushed @@ -23,15 +32,6 @@ import '../../../zds_flutter.dart'; /// /// * [showDatePicker], which is a way to display the date picker. class DatePickerDialog extends StatefulWidget { - static const Size _calendarPortraitDialogSize = Size(330, 518); - static const Size _calendarLandscapeDialogSize = Size(496, 346); - static const Size _inputPortraitDialogSize = Size(330, 270); - static const Size _inputLandscapeDialogSize = Size(496, 160); - static const Size _inputRangeLandscapeDialogSize = Size(496, 164); - static const Duration _dialogSizeAnimationDuration = Duration(milliseconds: 200); - static const double _inputFormPortraitHeight = 98; - static const double _inputFormLandscapeHeight = 108; - /// A Material-style date picker dialog. DatePickerDialog({ required DateTime initialDate, @@ -144,6 +144,7 @@ class DatePickerDialog extends StatefulWidget { @override State createState() => _DatePickerDialogState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -229,17 +230,17 @@ class _DatePickerDialogState extends State with RestorationMix case DatePickerEntryMode.calendarOnly: switch (orientation) { case Orientation.portrait: - return DatePickerDialog._calendarPortraitDialogSize; + return _calendarPortraitDialogSize; case Orientation.landscape: - return DatePickerDialog._calendarLandscapeDialogSize; + return _calendarLandscapeDialogSize; } case DatePickerEntryMode.input: case DatePickerEntryMode.inputOnly: switch (orientation) { case Orientation.portrait: - return DatePickerDialog._inputPortraitDialogSize; + return _inputPortraitDialogSize; case Orientation.landscape: - return DatePickerDialog._inputLandscapeDialogSize; + return _inputLandscapeDialogSize; } } } @@ -304,9 +305,7 @@ class _DatePickerDialogState extends State with RestorationMix key: _formKey, child: Container( padding: const EdgeInsets.symmetric(horizontal: 24), - height: orientation == Orientation.portrait - ? DatePickerDialog._inputFormPortraitHeight - : DatePickerDialog._inputFormLandscapeHeight, + height: orientation == Orientation.portrait ? _inputFormPortraitHeight : _inputFormLandscapeHeight, child: Shortcuts( shortcuts: _formShortcutMap, child: Column( @@ -379,7 +378,7 @@ class _DatePickerDialogState extends State with RestorationMix child: AnimatedContainer( width: dialogSize.width, height: dialogSize.height, - duration: DatePickerDialog._dialogSizeAnimationDuration, + duration: _dialogSizeAnimationDuration, curve: Curves.easeIn, child: MediaQuery( data: MediaQuery.of(context).copyWith( @@ -460,7 +459,8 @@ class _RestorableDatePickerEntryMode extends RestorableValue showRflxDateRangePicker({ + required DateTime firstDate, + required DateTime lastDate, + required BuildContext context, + DateTimeRange? initialDateRange, + DateTime? currentDate, + DatePickerEntryMode initialEntryMode = DatePickerEntryMode.calendar, + String? helpText, + String? cancelText, + String? confirmText, + String? saveText, + String? errorFormatText, + String? errorInvalidText, + String? errorInvalidRangeText, + String? fieldStartHintText, + String? fieldEndHintText, + String? fieldStartLabelText, + String? fieldEndLabelText, + String? clearButtonString, + String? applyButtonString, + Locale? locale, + bool useRootNavigator = true, + RouteSettings? routeSettings, + TextDirection? textDirection, + TransitionBuilder? builder, + List? actions, + bool isWeekMode = false, + int startingDayOfWeek = 0, +}) async => + showZdsDateRangePicker( + firstDate: firstDate, + lastDate: lastDate, + context: context, + initialDateRange: initialDateRange, + currentDate: currentDate, + initialEntryMode: initialEntryMode, + helpText: helpText, + cancelText: cancelText, + confirmText: confirmText, + saveText: saveText, + errorFormatText: errorFormatText, + errorInvalidText: errorInvalidText, + errorInvalidRangeText: errorInvalidRangeText, + fieldStartHintText: fieldStartHintText, + fieldEndHintText: fieldEndHintText, + fieldStartLabelText: fieldStartLabelText, + fieldEndLabelText: fieldEndLabelText, + clearButtonString: clearButtonString, + applyButtonString: applyButtonString, + locale: locale, + useRootNavigator: useRootNavigator, + routeSettings: routeSettings, + textDirection: textDirection, + builder: builder, + actions: actions, + isWeekMode: isWeekMode, + startingDayOfWeek: startingDayOfWeek, + ); + /// Shows a full screen modal dialog containing a Material Design date range /// picker. /// @@ -631,10 +692,15 @@ class _DatePickerHeader extends StatelessWidget { /// [lastDate]. For all of these [DateTime] values, only their dates are /// considered. Their time fields are ignored. /// -/// The [currentDate] represents the current day (ie today). This +/// The [currentDate] represents the current day (i.e. today). This /// date will be highlighted in the day grid. If null, the date of /// `DateTime.now()` will be used. /// +/// An optional [initialEntryMode] argument can be used to display the date +/// picker in the [DatePickerEntryMode.calendar] (a scrollable calendar month +/// grid) or [DatePickerEntryMode.input] (two text input fields) mode. +/// It defaults to [DatePickerEntryMode.calendar] and must be non-null. +/// /// The following optional string parameters allow you to override the default /// text used for various parts of the dialog: /// @@ -648,7 +714,7 @@ class _DatePickerHeader extends StatelessWidget { /// * [errorInvalidText], the message used when an input text isn't a /// selectable date. /// * [errorInvalidRangeText], the message used when the date range is -/// invalid (eg start date is after end date). +/// invalid (e.g. start date is after end date). /// * [fieldStartHintText], the text used to prompt the user when no text has /// been entered in the start field. /// * [fieldEndHintText], the text used to prompt the user when no text has @@ -771,6 +837,7 @@ class _DatePickerHeader extends StatelessWidget { /// * [showDatePicker], which shows a material design date picker used to /// select a single date. /// * [DateTimeRange], which is used to describe a date range. +/// Future showZdsDateRangePicker({ required DateTime firstDate, required DateTime lastDate, @@ -799,6 +866,8 @@ Future showZdsDateRangePicker({ List? actions, bool isWeekMode = false, int startingDayOfWeek = 0, + String? shortMonthDayFormat, + String? shortDateFormat, }) async { assert( initialDateRange == null || !initialDateRange.start.isAfter(initialDateRange.end), @@ -852,6 +921,8 @@ Future showZdsDateRangePicker({ fieldEndLabelText: fieldEndLabelText, isWeekMode: isWeekMode, startDayOfWeek: startingDayOfWeek, + shortMonthDayFormat: shortMonthDayFormat, + shortDateFormat: shortDateFormat, ); if (textDirection != null) { @@ -885,12 +956,20 @@ Future showZdsDateRangePicker({ /// is in the same year as the `endDate` then it will use the short month /// day format (i.e. 'Jan 21'). Otherwise it will return the short date format /// (i.e. 'Jan 21, 2020'). -String _formatRangeStartDate(MaterialLocalizations localizations, DateTime? startDate, DateTime? endDate) { +String _formatRangeStartDate( + MaterialLocalizations localizations, + DateTime? startDate, + DateTime? endDate, + String? shortMonthDayFormat, + String? shortDateFormat, +) { return startDate == null ? localizations.dateRangeStartLabel : (endDate == null || startDate.year == endDate.year) - ? localizations.formatShortMonthDay(startDate) - : localizations.formatShortDate(startDate); + ? (shortMonthDayFormat != null + ? startDate.format(shortMonthDayFormat) + : localizations.formatShortMonthDay(startDate)) + : (shortDateFormat != null ? startDate.format(shortDateFormat) : localizations.formatShortDate(startDate)); } /// Returns an locale-appropriate string to describe the end of a date range. @@ -904,12 +983,16 @@ String _formatRangeEndDate( DateTime? startDate, DateTime? endDate, DateTime currentDate, + String? shortMonthDayFormat, + String? shortDateFormat, ) { return endDate == null ? localizations.dateRangeEndLabel : (startDate != null && startDate.year == endDate.year && startDate.year == currentDate.year) - ? localizations.formatShortMonthDay(endDate) - : localizations.formatShortDate(endDate); + ? (shortMonthDayFormat != null + ? endDate.format(shortMonthDayFormat) + : localizations.formatShortMonthDay(endDate)) + : (shortDateFormat != null ? endDate.format(shortDateFormat) : localizations.formatShortDate(endDate)); } /// A Material-style date range picker dialog. @@ -946,9 +1029,11 @@ class ZdsDateRangePickerDialog extends StatefulWidget { this.clearButtonString, this.applyButtonString, this.isWeekMode = false, - this.startDayOfWeek = 0, + this.startDayOfWeek, + this.shortMonthDayFormat, + this.shortDateFormat, }) : assert( - !isWeekMode || (startDayOfWeek >= 0 && startDayOfWeek <= 6), + !isWeekMode || startDayOfWeek == null || (startDayOfWeek >= 0 && startDayOfWeek <= 6), 'startingDayOfWeek must be an int between 0 and 6 inclusive', ); @@ -973,7 +1058,7 @@ class ZdsDateRangePickerDialog extends StatefulWidget { /// The latest allowable date on the date range. final DateTime lastDate; - /// The [currentDate] represents the current day (ie today). + /// The [currentDate] represents the current day (i.e. today). /// /// This date will be highlighted in the day grid. /// @@ -1013,7 +1098,7 @@ class ZdsDateRangePickerDialog extends StatefulWidget { /// [MaterialLocalizations.dateRangePickerHelpText] is used. final String? helpText; - /// The message used when the date range is invalid (eg start date is after + /// The message used when the date range is invalid (e.g. start date is after /// end date). /// /// If null, the localized value of @@ -1092,10 +1177,17 @@ class ZdsDateRangePickerDialog extends StatefulWidget { /// 0 indexed where Sunday is 0 and Saturday is 6 /// /// Defaults to 0. - final int startDayOfWeek; + final int? startDayOfWeek; + + /// This is month format that comes on picker header when dates selected are from same year this format should not contain year. + final String? shortMonthDayFormat; + + /// This is complete date format that comes on picker header when dates selected are from two different year and it must contain year format. + final String? shortDateFormat; @override State createState() => _ZdsDateRangePickerDialogState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -1120,7 +1212,9 @@ class ZdsDateRangePickerDialog extends StatefulWidget { ..add(StringProperty('clearButtonString', clearButtonString)) ..add(StringProperty('applyButtonString', applyButtonString)) ..add(DiagnosticsProperty('isWeekMode', isWeekMode)) - ..add(IntProperty('startDayOfWeek', startDayOfWeek)); + ..add(IntProperty('startDayOfWeek', startDayOfWeek)) + ..add(StringProperty('shortMonthDayFormat', shortMonthDayFormat)) + ..add(StringProperty('shortDateFormat', shortDateFormat)); } } @@ -1242,7 +1336,7 @@ class _ZdsDateRangePickerDialogState extends State wit onCancel: _handleCancel, actions: widget.actions, isWeekMode: widget.isWeekMode, - startDayOfWeek: widget.startDayOfWeek, + startDayOfWeek: widget.startDayOfWeek ?? localizations.firstDayOfWeekIndex, entryModeButton: showEntryModeButton ? IconButton( icon: const Icon(Icons.edit), @@ -1254,6 +1348,8 @@ class _ZdsDateRangePickerDialogState extends State wit : null, confirmText: widget.saveText ?? localizations.saveButtonLabel, helpText: widget.helpText ?? localizations.dateRangePickerHelpText, + shortMonthDayFormat: widget.shortMonthDayFormat, + shortDateFormat: widget.shortDateFormat, ); size = mediaQuery.size; insetPadding = EdgeInsets.zero; @@ -1268,9 +1364,7 @@ class _ZdsDateRangePickerDialogState extends State wit currentDate: widget.currentDate, picker: Container( padding: const EdgeInsets.symmetric(horizontal: 24), - height: orientation == Orientation.portrait - ? DatePickerDialog._inputFormPortraitHeight - : DatePickerDialog._inputFormLandscapeHeight, + height: orientation == Orientation.portrait ? _inputFormPortraitHeight : _inputFormLandscapeHeight, child: Column( children: [ const Spacer(), @@ -1311,11 +1405,11 @@ class _ZdsDateRangePickerDialogState extends State wit confirmText: widget.confirmText ?? localizations.okButtonLabel, cancelText: widget.cancelText ?? localizations.cancelButtonLabel, helpText: widget.helpText ?? localizations.dateRangePickerHelpText, + shortMonthDayFormat: widget.shortMonthDayFormat, + shortDateFormat: widget.shortDateFormat, ); final DialogTheme dialogTheme = Theme.of(context).dialogTheme; - size = orientation == Orientation.portrait - ? DatePickerDialog._inputPortraitDialogSize - : DatePickerDialog._inputRangeLandscapeDialogSize; + size = orientation == Orientation.portrait ? _inputPortraitDialogSize : _inputRangeLandscapeDialogSize; insetPadding = const EdgeInsets.symmetric(horizontal: 16, vertical: 24); shape = dialogTheme.shape; elevation = dialogTheme.elevation ?? 24; @@ -1329,7 +1423,7 @@ class _ZdsDateRangePickerDialogState extends State wit child: AnimatedContainer( width: size.width, height: size.height, - duration: DatePickerDialog._dialogSizeAnimationDuration, + duration: _dialogSizeAnimationDuration, curve: Curves.easeIn, child: MediaQuery( data: MediaQuery.of(context).copyWith( @@ -1366,6 +1460,8 @@ class _CalendarRangePickerDialog extends StatelessWidget { this.applyButtonString, this.isWeekMode = false, this.startDayOfWeek = 0, + this.shortMonthDayFormat, + this.shortDateFormat, }) : assert( !isWeekMode || (startDayOfWeek >= 0 && startDayOfWeek <= 6), 'startingDayOfWeek must be an int between 0 and 6 inclusive', @@ -1388,26 +1484,47 @@ class _CalendarRangePickerDialog extends StatelessWidget { final String? applyButtonString; final bool isWeekMode; final int startDayOfWeek; + final String? shortMonthDayFormat; + final String? shortDateFormat; @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final ColorScheme colorScheme = theme.colorScheme; final MaterialLocalizations localizations = MaterialLocalizations.of(context); final Orientation orientation = MediaQuery.of(context).orientation; + final zetaColors = Zeta.of(context).colors; + final TextTheme textTheme = theme.textTheme; - final Color headerForeground = colorScheme.onPrimary; - final Color headerDisabledForeground = headerForeground.withOpacity(0.38); - final String startDateText = _formatRangeStartDate(localizations, selectedStartDate, selectedEndDate); - final String endDateText = _formatRangeEndDate(localizations, selectedStartDate, selectedEndDate, DateTime.now()); - final TextStyle? headlineStyle = textTheme.headlineSmall; + final Color headerForeground = zetaColors.textDefault; + final Color headerDisabledForeground = zetaColors.textDisabled; + + final String startDateText = _formatRangeStartDate( + localizations, + selectedStartDate, + selectedEndDate, + shortMonthDayFormat, + shortDateFormat, + ); + + final String endDateText = _formatRangeEndDate( + localizations, + selectedStartDate, + selectedEndDate, + DateTime.now(), + shortMonthDayFormat, + shortDateFormat, + ); + + final TextStyle? headlineStyle = textTheme.displaySmall; final TextStyle? startDateStyle = headlineStyle?.apply( color: selectedStartDate != null ? headerForeground : headerDisabledForeground, ); + final TextStyle? endDateStyle = headlineStyle?.apply( color: selectedEndDate != null ? headerForeground : headerDisabledForeground, ); - final TextStyle saveButtonStyle = textTheme.labelLarge!.apply( + + final TextStyle saveButtonStyle = safeTextStyle(textTheme.labelLarge).apply( color: onConfirm != null ? headerForeground : headerDisabledForeground, ); @@ -1442,7 +1559,10 @@ class _CalendarRangePickerDialog extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, ), - Text(' - ', style: startDateStyle), + Text( + ' – ', + style: startDateStyle, + ), Flexible( child: Text( endDateText, @@ -1484,12 +1604,12 @@ class _CalendarRangePickerDialog extends StatelessWidget { const Spacer(), ZdsButton.outlined( onTap: onCancel, - child: Text(clearButtonString ?? ComponentStrings.of(context).get('CLEAR', 'Clear')), + child: Text(clearButtonString ?? 'Clear'), ), const SizedBox(width: 8), ZdsButton( onTap: onConfirm, - child: Text(applyButtonString ?? ComponentStrings.of(context).get('APPLY', 'Apply')), + child: Text(applyButtonString ?? 'Apply'), ), ], ), @@ -1515,7 +1635,9 @@ class _CalendarRangePickerDialog extends StatelessWidget { ..add(StringProperty('clearButtonString', clearButtonString)) ..add(StringProperty('applyButtonString', applyButtonString)) ..add(DiagnosticsProperty('isWeekMode', isWeekMode)) - ..add(IntProperty('startDayOfWeek', startDayOfWeek)); + ..add(IntProperty('startDayOfWeek', startDayOfWeek)) + ..add(StringProperty('shortMonthDayFormat', shortMonthDayFormat)) + ..add(StringProperty('shortDateFormat', shortDateFormat)); } } @@ -1589,10 +1711,11 @@ class _CalendarDateRangePicker extends StatefulWidget { /// 0 indexed where Sunday is 0 and Saturday is 6 /// /// Defaults to 0. - final int startDayOfWeek; + final int? startDayOfWeek; @override _CalendarDateRangePickerState createState() => _CalendarDateRangePickerState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -1697,13 +1820,21 @@ class _CalendarDateRangePickerState extends State<_CalendarDateRangePicker> { } if (widget.isWeekMode) { - widget.onStartDateChanged?.call(_startDate = date.getFirstDayOfWeek(weekStartDay: widget.startDayOfWeek)); - widget.onEndDateChanged?.call(_endDate = date.getLastDayOfWeek(weekStartDay: widget.startDayOfWeek)); + widget.onStartDateChanged?.call( + _startDate = date.getFirstDayOfWeek( + weekStartDay: widget.startDayOfWeek ?? MaterialLocalizations.of(context).firstDayOfWeekIndex, + ), + ); + widget.onEndDateChanged?.call( + _endDate = date.getLastDayOfWeek( + weekStartDay: widget.startDayOfWeek ?? MaterialLocalizations.of(context).firstDayOfWeekIndex, + ), + ); } }); } - Widget _buildMonthItem(int index, bool beforeInitialMonth) { + Widget _buildMonthItem(BuildContext context, int index, bool beforeInitialMonth) { final int monthIndex = beforeInitialMonth ? _initialMonthIndex - index - 1 : _initialMonthIndex + index; final DateTime month = DateUtils.addMonthsToMonthDate(widget.firstDate, monthIndex); return MonthItem( @@ -1712,6 +1843,7 @@ class _CalendarDateRangePickerState extends State<_CalendarDateRangePicker> { currentDate: widget.currentDate, firstDate: widget.firstDate, lastDate: widget.lastDate, + firstDayOfWeek: widget.startDayOfWeek, displayedMonth: month, onChanged: _updateSelection, ); @@ -1723,7 +1855,9 @@ class _CalendarDateRangePickerState extends State<_CalendarDateRangePicker> { return Column( children: [ - _DayHeaders(), + _DayHeaders( + firstDayOfWeek: widget.startDayOfWeek, + ), if (_showWeekBottomDivider) const Divider(height: 0), Expanded( child: _CalendarKeyboardNavigator( @@ -1741,14 +1875,14 @@ class _CalendarDateRangePickerState extends State<_CalendarDateRangePicker> { slivers: [ SliverList( delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) => _buildMonthItem(index, true), + (BuildContext context, int index) => _buildMonthItem(context, index, true), childCount: _initialMonthIndex, ), ), SliverList( key: sliverAfterKey, delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) => _buildMonthItem(index, false), + (BuildContext context, int index) => _buildMonthItem(context, index, false), childCount: _numberOfMonths - _initialMonthIndex, ), ), @@ -1776,6 +1910,7 @@ class _CalendarKeyboardNavigator extends StatefulWidget { @override _CalendarKeyboardNavigatorState createState() => _CalendarKeyboardNavigatorState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -1825,14 +1960,14 @@ class _CalendarKeyboardNavigatorState extends State<_CalendarKeyboardNavigator> } /// Move focus to the next element after the day grid. - void _handleGridNextFocus(_) { + void _handleGridNextFocus(NextFocusIntent intent) { _dayGridFocus ..requestFocus() ..nextFocus(); } /// Move focus to the previous element before the day grid. - void _handleGridPreviousFocus(_) { + void _handleGridPreviousFocus(PreviousFocusIntent intent) { _dayGridFocus ..requestFocus() ..previousFocus(); @@ -1866,16 +2001,16 @@ class _CalendarKeyboardNavigatorState extends State<_CalendarKeyboardNavigator> }; int _dayDirectionOffset(TraversalDirection traversalDirection, TextDirection textDirection) { - TraversalDirection td = traversalDirection; // Swap left and right if the text direction if RTL + TraversalDirection effectiveDirection = traversalDirection; if (textDirection == TextDirection.rtl) { - if (traversalDirection == TraversalDirection.left) { - td = TraversalDirection.right; - } else if (traversalDirection == TraversalDirection.right) { - td = TraversalDirection.left; + if (effectiveDirection == TraversalDirection.left) { + effectiveDirection = TraversalDirection.right; + } else if (effectiveDirection == TraversalDirection.right) { + effectiveDirection = TraversalDirection.left; } } - return _directionOffset[td] ?? 0; + return _directionOffset[effectiveDirection]!; } DateTime? _nextDateInDirection(DateTime date, TraversalDirection direction) { @@ -1905,7 +2040,6 @@ class _CalendarKeyboardNavigatorState extends State<_CalendarKeyboardNavigator> /// InheritedWidget indicating what the current focused date is for its children. /// -/// This is used by the [MonthItem] to let its children know what the currently focused date (if any) should be. class _FocusedDate extends InheritedWidget { const _FocusedDate({ required super.child, @@ -1935,19 +2069,23 @@ class _FocusedDate extends InheritedWidget { } class _DayHeaders extends StatelessWidget { + const _DayHeaders({this.firstDayOfWeek}); + + final int? firstDayOfWeek; + /// Builds widgets showing abbreviated days of week. The first widget in the /// returned list corresponds to the first day of week for the current locale. /// /// Examples: /// /// ``` - /// ┌ Sunday is the first day of week in the US (en_US) + /// ┌ [firsDayOfWeek] is 0 then its point to Sunday which is the first day of week in the US (en_US) /// | /// S M T W T F S <-- the returned list contains these widgets /// _ _ _ _ _ 1 2 /// 3 4 5 6 7 8 9 /// - /// ┌ But it's Monday in the UK (en_GB) + /// ┌ But if 1 then it's Monday in the UK (en_GB) /// | /// M T W T F S S <-- the returned list contains these widgets /// _ _ _ _ 1 2 3 @@ -1955,17 +2093,14 @@ class _DayHeaders extends StatelessWidget { /// ``` List _getDayHeaders(TextStyle headerStyle, MaterialLocalizations localizations) { final List result = []; - bool foundFlag = false; - int iterator = localizations.firstDayOfWeekIndex; - while (!foundFlag) { - final String weekday = localizations.narrowWeekdays[iterator]; + final fistDayNo = firstDayOfWeek ?? localizations.firstDayOfWeekIndex; + final weekNarrowList = rotateArrayLeft(localizations.narrowWeekdays, fistDayNo); + for (final weekDay in weekNarrowList) { result.add( ExcludeSemantics( - child: Center(child: Text(weekday, style: headerStyle)), + child: Center(child: Text(weekDay, style: headerStyle)), ), ); - if (iterator == (localizations.firstDayOfWeekIndex - 1) % 7) foundFlag = true; - iterator = (iterator + 1) % 7; } return result; } @@ -1999,6 +2134,12 @@ class _DayHeaders extends StatelessWidget { ), ); } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(IntProperty('firstDayOfWeek', firstDayOfWeek)); + } } class _MonthItemGridDelegate extends SliverGridDelegate { @@ -2006,7 +2147,7 @@ class _MonthItemGridDelegate extends SliverGridDelegate { @override SliverGridLayout getLayout(SliverConstraints constraints) { - final double tileWidth = (constraints.crossAxisExtent - _horizontalPadding * 2) / DateTime.daysPerWeek; + final double tileWidth = (constraints.crossAxisExtent - 2 * _horizontalPadding) / DateTime.daysPerWeek; return _MonthSliverGridLayout( crossAxisCount: DateTime.daysPerWeek + 2, dayChildWidth: tileWidth, @@ -2081,7 +2222,7 @@ class _MonthSliverGridLayout extends SliverGridLayout { double _getCrossAxisOffset(double crossAxisStart, bool isPadding) { if (reverseCrossAxis) { - return ((crossAxisCount - 2) * dayChildWidth + edgeChildWidth * 2) - + return ((crossAxisCount - 2) * dayChildWidth + 2 * edgeChildWidth) - crossAxisStart - (isPadding ? edgeChildWidth : dayChildWidth); } @@ -2127,6 +2268,7 @@ class MonthItem extends StatefulWidget { required this.displayedMonth, super.key, this.dragStartBehavior = DragStartBehavior.start, + this.firstDayOfWeek, }) : assert(!firstDate.isAfter(lastDate), 'firstDate must be before lastDate.'), assert( selectedDateStart == null || !selectedDateStart.isBefore(firstDate), @@ -2149,6 +2291,9 @@ class MonthItem extends StatefulWidget { 'selectedDateStart must be before selectedDateEnd.', ); + /// first day of week + final int? firstDayOfWeek; + /// The currently selected start date. /// /// This date is highlighted in the picker. @@ -2189,15 +2334,20 @@ class MonthItem extends StatefulWidget { /// /// See also: /// - /// * [DragStartBehavior], which gives an example for the different behaviors. + // ignore: comment_references + /// * [DragGestureRecognizer.dragStartBehavior], which gives an example for + /// the different behaviors. final DragStartBehavior dragStartBehavior; @override MonthItemState createState() => MonthItemState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); + properties + ..add(IntProperty('firstDayOfWeek', firstDayOfWeek)) ..add(DiagnosticsProperty('selectedDateStart', selectedDateStart)) ..add(DiagnosticsProperty('selectedDateEnd', selectedDateEnd)) ..add(DiagnosticsProperty('currentDate', currentDate)) @@ -2255,7 +2405,6 @@ class MonthItemState extends State { case TraversalDirection.up: case TraversalDirection.left: policy = ScrollPositionAlignmentPolicy.keepVisibleAtStart; - case TraversalDirection.right: case TraversalDirection.down: policy = ScrollPositionAlignmentPolicy.keepVisibleAtEnd; @@ -2271,7 +2420,7 @@ class MonthItemState extends State { } } - Widget _buildDayItem(BuildContext context, DateTime dayToBuild) { + Widget _buildDayItem(BuildContext context, DateTime dayToBuild, int firstDayOffset, int daysInMonth) { final ThemeData theme = Theme.of(context); final ColorScheme colorScheme = theme.colorScheme; final TextTheme textTheme = theme.textTheme; @@ -2282,7 +2431,7 @@ class MonthItemState extends State { final bool isDisabled = dayToBuild.isAfter(widget.lastDate) || dayToBuild.isBefore(widget.firstDate); - BoxDecoration decoration = const BoxDecoration(); + BoxDecoration? decoration; TextStyle? itemStyle = textTheme.bodyMedium; final bool isRangeSelected = widget.selectedDateStart != null && widget.selectedDateEnd != null; @@ -2328,7 +2477,7 @@ class MonthItemState extends State { // border. itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.secondary); decoration = BoxDecoration( - border: Border.fromBorderSide(BorderSide(color: colorScheme.secondary)), + border: Border.all(color: colorScheme.secondary), shape: BoxShape.circle, ); } @@ -2346,7 +2495,8 @@ class MonthItemState extends State { semanticLabel = localizations.dateRangeEndDateSemanticLabel(semanticLabel); } - Widget dayWidget = DecoratedBox( + // ignore: use_decorated_box + Widget dayWidget = Container( decoration: decoration, child: Center( child: Semantics( @@ -2384,6 +2534,23 @@ class MonthItemState extends State { return Container(color: isHighlighted ? _highlightColor(context) : null); } + /// for firstDayOfWeek 0 points to sunday + static int _firstDayOffset(int year, int month, int? firstDayOfWeek, MaterialLocalizations localizations) { + // 0-based day of week for the month and year, with 0 representing Monday. + final int weekdayFromMonday = DateTime(year, month).weekday - 1; + + // 0-based start of week depending on the locale, with 0 representing Sunday. + int firstDayOfWeekIndex = firstDayOfWeek ?? localizations.firstDayOfWeekIndex; + + // firstDayOfWeekIndex recomputed to be Monday-based, in order to compare with + // weekdayFromMonday. + firstDayOfWeekIndex = (firstDayOfWeekIndex - 1) % 7; + + // Number of days between the first day of week appearing on the calendar, + // and the day corresponding to the first of the month. + return (weekdayFromMonday - firstDayOfWeekIndex) % 7; + } + @override Widget build(BuildContext context) { final ThemeData themeData = Theme.of(context); @@ -2392,7 +2559,7 @@ class MonthItemState extends State { final int year = widget.displayedMonth.year; final int month = widget.displayedMonth.month; final int daysInMonth = DateUtils.getDaysInMonth(year, month); - final int dayOffset = DateUtils.firstDayOffset(year, month, localizations); + final int dayOffset = _firstDayOffset(year, month, widget.firstDayOfWeek, localizations); final int weeks = ((daysInMonth + dayOffset) / DateTime.daysPerWeek).ceil(); final double gridHeight = weeks * _monthItemRowHeight + (weeks - 1) * _monthItemSpaceBetweenRows; final List dayItems = []; @@ -2406,7 +2573,12 @@ class MonthItemState extends State { dayItems.add(const SizedBox()); } else { final DateTime dayToBuild = DateTime(year, month, day); - final Widget dayItem = _buildDayItem(context, dayToBuild); + final Widget dayItem = _buildDayItem( + context, + dayToBuild, + dayOffset, + daysInMonth, + ); dayItems.add(dayItem); } iterator += 1; @@ -2542,7 +2714,6 @@ class _HighlightPainter extends CustomPainter { textDirection == TextDirection.ltr ? rectLeft : rectRight, paint, ); - case _HighlightPainterStyle.highlightAll: canvas.drawRect( Rect.fromLTWH(0, 0, size.width, size.height), @@ -2569,6 +2740,8 @@ class _InputDateRangePickerDialog extends StatelessWidget { required this.cancelText, required this.helpText, required this.entryModeButton, + this.shortMonthDayFormat, + this.shortDateFormat, }); final DateTime? selectedStartDate; @@ -2581,15 +2754,21 @@ class _InputDateRangePickerDialog extends StatelessWidget { final String? cancelText; final String? helpText; final Widget? entryModeButton; + final String? shortMonthDayFormat; + final String? shortDateFormat; String _formatDateRange(BuildContext context, DateTime? start, DateTime? end, DateTime now) { final MaterialLocalizations localizations = MaterialLocalizations.of(context); - final String startText = _formatRangeStartDate(localizations, start, end); - final String endText = _formatRangeEndDate(localizations, start, end, now); + final String startText = _formatRangeStartDate(localizations, start, end, shortMonthDayFormat, shortDateFormat); + final String endText = _formatRangeEndDate(localizations, start, end, now, shortMonthDayFormat, shortDateFormat); if (start == null || end == null) { return localizations.unspecifiedDateRange; } - return Directionality.of(context) == TextDirection.ltr ? '$startText - $endText' : '$endText - $startText'; + if (Directionality.of(context) == TextDirection.ltr) { + return '$startText – $endText'; + } else { + return '$endText – $startText'; + } } @override @@ -2607,7 +2786,7 @@ class _InputDateRangePickerDialog extends StatelessWidget { : textTheme.headlineMedium?.apply(color: onPrimarySurfaceColor); final String dateText = _formatDateRange(context, selectedStartDate, selectedEndDate, currentDate!); final String semanticDateText = selectedStartDate != null && selectedEndDate != null - ? '${localizations.formatMediumDate(selectedStartDate!)} - ${localizations.formatMediumDate(selectedEndDate!)}' + ? '${localizations.formatMediumDate(selectedStartDate!)} – ${localizations.formatMediumDate(selectedEndDate!)}' : ''; final Widget header = _DatePickerHeader( @@ -2683,7 +2862,9 @@ class _InputDateRangePickerDialog extends StatelessWidget { ..add(ObjectFlagProperty.has('onCancel', onCancel)) ..add(StringProperty('confirmText', confirmText)) ..add(StringProperty('cancelText', cancelText)) - ..add(StringProperty('helpText', helpText)); + ..add(StringProperty('helpText', helpText)) + ..add(StringProperty('shortMonthDayFormat', shortMonthDayFormat)) + ..add(StringProperty('shortDateFormat', shortDateFormat)); } } @@ -2746,7 +2927,7 @@ class _InputDateRangePicker extends StatefulWidget { final String? errorInvalidText; /// Error text used to indicate the dates given don't form a valid date - /// range (ie the start date is after the end date). + /// range (i.e. the start date is after the end date). final String? errorInvalidRangeText; /// Hint text shown when the start date field is empty. @@ -2771,6 +2952,7 @@ class _InputDateRangePicker extends StatefulWidget { @override _InputDateRangePickerState createState() => _InputDateRangePickerState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); diff --git a/lib/src/components/molecules/date_time_picker.dart b/lib/src/components/molecules/date_time_picker.dart index 9adc0de..812d30d 100644 --- a/lib/src/components/molecules/date_time_picker.dart +++ b/lib/src/components/molecules/date_time_picker.dart @@ -1,21 +1,28 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart' hide DatePickerDialog; +import 'package:flutter/material.dart'; import 'package:interval_time_picker/interval_time_picker.dart' as interval_picker; + import 'package:intl/intl.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/localizations/translation.dart'; +import '../../utils/theme/input_border.dart'; +import '../../utils/theme/theme.dart'; +import '../../utils/tools/controller.dart'; +import '../organisms/date_range_picker_tile.dart'; +import '../organisms/fiscal_date_picker.dart'; /// Variants of [ZdsDateTimePicker]. enum DateTimePickerMode { - /// Creates and shows a [DatePickerDialog] with Zds style and behavior. + /// Creates and shows a [ZdsDatePickerDialog] with Zebra style and behavior. date, - /// Creates and shows a [TimePickerDialog] with Zds style and behavior. + /// Creates and shows a [TimePickerDialog] with Zebra style and behavior. time, - /// Creates and shows first a [DatePickerDialog] and then a [TimePickerDialog] with Zds style and behavior. + /// Creates and shows first a [ZdsDatePickerDialog] and then a [TimePickerDialog] with Zebra style and behavior. dateAndTime } @@ -23,11 +30,11 @@ enum DateTimePickerMode { /// /// A [controller] can be used to handle this date and use it to manage state. /// -/// This widget is typically used as a non-editable textfield by using [ZdsInputDecoration] for [inputDecoration]. +/// This widget is typically used as a non-editable text field by using [ZdsInputDecoration] for [inputDecoration]. /// It can also be used as a button on its own by not assigning any [inputDecoration]. /// /// ```dart -/// // As a textfield +/// // As a text field /// ZdsDateTimePicker( /// emptyLabel: 'select date', /// minDate: DateTime.now(), @@ -54,8 +61,45 @@ enum DateTimePickerMode { /// See also: /// /// * [ZdsDateRangePickerTile], which allows to select a date range's start and end time separately. -/// * [showDatePicker] to show a date picker directly class ZdsDateTimePicker extends StatefulWidget { + /// Constructs a [ZdsDateTimePicker]. + ZdsDateTimePicker({ + required this.emptyLabel, + super.key, + String? format, + this.mode = DateTimePickerMode.date, + this.textAlign = TextAlign.start, + this.helpText, + this.helpTextStyle, + this.minDate, + this.maxDate, + this.selectedDate, + this.textStyle, + this.onChange, + this.padding, + this.inputDecoration, + this.controller, + this.readOnly = false, + this.interval, + this.visibleStep = interval_picker.VisibleStep.fifths, + this.timePickerErrorText, + this.use24HourFormat, + this.timePickerEntryMode = TimePickerEntryMode.inputOnly, + this.okClickText, + this.cancelClickText, + this.startDayOfWeek, + }) : format = (format?.isNotEmpty ?? false) + ? format! + : (mode == DateTimePickerMode.date + ? 'MMM dd, yyyy' + : mode == DateTimePickerMode.time + ? 'hh:mm a' + : 'MMM dd, yyyy hh:mm a'), + assert( + (minDate != null && maxDate != null) ? minDate.isBefore(maxDate) : (minDate == null || maxDate == null), + 'minDate must be before maxDate.', + ); + /// The type of picker to show - `date`, `time` or `dateAndTime`. final DateTimePickerMode mode; @@ -128,66 +172,45 @@ class ZdsDateTimePicker extends StatefulWidget { /// Initial entry mode for time pickers. final TimePickerEntryMode timePickerEntryMode; - /// Constructs a [ZdsDateTimePicker]. - ZdsDateTimePicker({ - required this.emptyLabel, - super.key, - String? format, - this.mode = DateTimePickerMode.date, - this.textAlign = TextAlign.start, - this.helpText, - this.helpTextStyle, - this.minDate, - this.maxDate, - this.selectedDate, - this.textStyle, - this.onChange, - this.padding, - this.inputDecoration, - this.controller, - this.readOnly = false, - this.interval, - this.visibleStep = interval_picker.VisibleStep.fifths, - this.timePickerErrorText, - this.use24HourFormat, - this.timePickerEntryMode = TimePickerEntryMode.inputOnly, - }) : format = (format?.isNotEmpty ?? false) - ? format! - : (mode == DateTimePickerMode.date - ? 'MMM dd, yyyy' - : mode == DateTimePickerMode.time - ? 'hh:mm a' - : 'MMM dd, yyyy hh:mm a'), - assert( - (minDate != null && maxDate != null) ? minDate.isBefore(maxDate) : (minDate == null || maxDate == null), - 'minDate must be before maxDate.', - ); + /// The text displayed on the ok button. + final String? okClickText; + + /// The text displayed on the cancel button. + final String? cancelClickText; + + /// Starting day of week 1, 2, 3, Sunday, Monday, Tuesday respectively. + final int? startDayOfWeek; @override ZdsDateTimePickerState createState() => ZdsDateTimePickerState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(EnumProperty('mode', mode)); - properties.add(StringProperty('format', format)); - properties.add(StringProperty('emptyLabel', emptyLabel)); - properties.add(StringProperty('helpText', helpText)); - properties.add(DiagnosticsProperty('helpTextStyle', helpTextStyle)); - properties.add(EnumProperty('textAlign', textAlign)); - properties.add(DiagnosticsProperty('minDate', minDate)); - properties.add(DiagnosticsProperty('maxDate', maxDate)); - properties.add(DiagnosticsProperty('readOnly', readOnly)); - properties.add(DiagnosticsProperty('selectedDate', selectedDate)); - properties.add(DiagnosticsProperty('textStyle', textStyle)); - properties.add(DiagnosticsProperty('padding', padding)); - properties.add(DiagnosticsProperty('inputDecoration', inputDecoration)); - properties.add(ObjectFlagProperty.has('onChange', onChange)); - properties.add(DiagnosticsProperty?>('controller', controller)); - properties.add(IntProperty('interval', interval)); - properties.add(EnumProperty('visibleStep', visibleStep)); - properties.add(StringProperty('timePickerErrorText', timePickerErrorText)); - properties.add(DiagnosticsProperty('use24HourFormat', use24HourFormat)); - properties.add(EnumProperty('timePickerEntryMode', timePickerEntryMode)); + properties + ..add(EnumProperty('mode', mode)) + ..add(StringProperty('format', format)) + ..add(StringProperty('emptyLabel', emptyLabel)) + ..add(StringProperty('helpText', helpText)) + ..add(DiagnosticsProperty('helpTextStyle', helpTextStyle)) + ..add(EnumProperty('textAlign', textAlign)) + ..add(DiagnosticsProperty('minDate', minDate)) + ..add(DiagnosticsProperty('maxDate', maxDate)) + ..add(DiagnosticsProperty('readOnly', readOnly)) + ..add(DiagnosticsProperty('selectedDate', selectedDate)) + ..add(DiagnosticsProperty('textStyle', textStyle)) + ..add(DiagnosticsProperty('padding', padding)) + ..add(DiagnosticsProperty('inputDecoration', inputDecoration)) + ..add(ObjectFlagProperty.has('onChange', onChange)) + ..add(DiagnosticsProperty?>('controller', controller)) + ..add(IntProperty('interval', interval)) + ..add(EnumProperty('visibleStep', visibleStep)) + ..add(StringProperty('timePickerErrorText', timePickerErrorText)) + ..add(DiagnosticsProperty('use24HourFormat', use24HourFormat)) + ..add(EnumProperty('timePickerEntryMode', timePickerEntryMode)) + ..add(StringProperty('okClickText', okClickText)) + ..add(StringProperty('cancelClickText', cancelClickText)) + ..add(IntProperty('startDayOfWeek', startDayOfWeek)); } } @@ -233,12 +256,13 @@ class ZdsDateTimePickerState extends State { @override Widget build(BuildContext context) { final textTheme = Theme.of(context).textTheme; + final zetaColors = Zeta.of(context).colors; Widget child = Text( _formattedDate.toLowerCase(), textAlign: widget.textAlign, style: widget.textStyle ?? textTheme.bodyLarge?.copyWith( - color: _dateTime == null ? ZdsColors.greySwatch(context)[600] : textTheme.bodyLarge?.color, + color: _dateTime == null ? zetaColors.textSubtle : textTheme.bodyLarge?.color, ), ); @@ -250,10 +274,10 @@ class ZdsDateTimePickerState extends State { } return Material( - color: ZdsColors.transparent, + color: Colors.transparent, child: InkWell( - splashColor: ZdsColors.splashColor, - hoverColor: ZdsColors.hoverColor, + splashColor: zetaColors.surfaceSelected, + hoverColor: zetaColors.surfaceSelectedHovered, radius: MediaQuery.of(context).size.width, onTap: () { if (!widget.readOnly) unawaited(onShowPicker(context, _dateTime)); @@ -264,8 +288,8 @@ class ZdsDateTimePickerState extends State { child: Semantics( label: _formattedDate == widget.emptyLabel ? '' : _formattedDate, excludeSemantics: true, - onTap: () async { - if (!widget.readOnly) await onShowPicker(context, _dateTime); + onTap: () { + if (!widget.readOnly) unawaited(onShowPicker(context, _dateTime)); }, child: Padding( padding: widget.padding ?? (widget.inputDecoration == null ? const EdgeInsets.all(16) : EdgeInsets.zero), @@ -277,10 +301,7 @@ class ZdsDateTimePickerState extends State { } /// Shows correct date or time picker for component. - Future onShowPicker( - BuildContext context, - DateTime? currentValue, - ) async { + Future onShowPicker(BuildContext context, DateTime? currentValue) async { DateTime? newValue; if (widget.mode == DateTimePickerMode.date) { @@ -289,11 +310,13 @@ class ZdsDateTimePickerState extends State { final newTime = await _showTimePicker(context, currentValue); newValue = newTime != null ? _convert(newTime) : null; } else { - final date = await _showDatePicker(context, currentValue); + final date = await _showDatePicker(context, currentValue ?? DateTime.now()); if (date != null) { if (mounted) { - final time = await _showTimePicker(context, date); - newValue = _combine(date, time); + final time = await _showTimePicker(context, currentValue ?? DateTime.now()); + if (time != null) { + newValue = _combine(date, time); + } } } } @@ -305,18 +328,15 @@ class ZdsDateTimePickerState extends State { }); } - Future _showDatePicker( - BuildContext context, - DateTime? currentValue, - ) { - return showDatePicker( + Future _showDatePicker(BuildContext context, DateTime? currentValue) { + return showZdsFiscalDatePicker( + format: widget.format, context: context, initialDate: currentValue ?? (widget.minDate != null && DateTime.now().isBefore(widget.minDate!) ? widget.minDate! : DateTime.now()), firstDate: widget.minDate ?? DateTime(1900), lastDate: widget.maxDate ?? DateTime(2100), - initialEntryMode: DatePickerEntryMode.calendarOnly, - helpText: widget.helpText, + titleText: widget.helpText ?? 'Select Date', builder: (context, child) { return Theme( data: Theme.of(context).zdsDateTimePickerTheme.copyWith( @@ -325,6 +345,9 @@ class ZdsDateTimePickerState extends State { child: child!, ); }, + cancelText: widget.cancelClickText ?? ComponentStrings.of(context).get('CANCEL', 'Cancel'), + okText: widget.okClickText ?? ComponentStrings.of(context).get('OK', 'OK'), + startDayOfWeek: widget.startDayOfWeek ?? 1, ); } @@ -339,10 +362,14 @@ class ZdsDateTimePickerState extends State { ); } + final initialValue = widget.interval == null + ? TimeOfDay.fromDateTime(currentValue ?? DateTime.now()) + : TimeOfDay.fromDateTime(currentValue ?? _roundDate(DateTime.now())); + final timePickerResult = widget.interval == null && mounted ? await showTimePicker( context: context, - initialTime: TimeOfDay.fromDateTime(currentValue ?? DateTime.now()), + initialTime: initialValue, initialEntryMode: widget.timePickerEntryMode, errorInvalidText: widget.timePickerErrorText, helpText: widget.helpText, @@ -351,7 +378,7 @@ class ZdsDateTimePickerState extends State { : mounted ? await interval_picker.showIntervalTimePicker( context: context, - initialTime: TimeOfDay.fromDateTime(currentValue ?? _roundDate(DateTime.now())), + initialTime: initialValue, interval: widget.interval!, visibleStep: widget.visibleStep, errorInvalidText: widget.timePickerErrorText, @@ -361,9 +388,9 @@ class ZdsDateTimePickerState extends State { ) : null; - final selectedTime = timePickerResult ?? (currentValue != null ? TimeOfDay.fromDateTime(currentValue) : null); + // final selectedTime = timePickerResult ?? (currentValue != null ? TimeOfDay.fromDateTime(currentValue) : null); - return selectedTime; + return timePickerResult; } interval_picker.TimePickerEntryMode _getIntervalPickerMode() { diff --git a/lib/src/components/molecules/dropdown.dart b/lib/src/components/molecules/dropdown.dart index cbc2d45..49e388d 100644 --- a/lib/src/components/molecules/dropdown.dart +++ b/lib/src/components/molecules/dropdown.dart @@ -2,25 +2,39 @@ import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Defines an item to be used in a [ZdsDropdownList] class ZdsDropdownListItem { - /// The value of the item - final T value; - - /// The name of the item - final String name; - /// Creates a new [ZdsDropdownListItem] ZdsDropdownListItem({ required this.value, required this.name, }); + + /// The value of the item + final T value; + + /// The name of the item + final String name; } /// A [DropdownButtonFormField] with Zds style and behavior. class ZdsDropdownList extends StatefulWidget { + /// Constructs a [ZdsDropdownList]. + const ZdsDropdownList({ + this.onChange, + this.onReset, + this.value, + this.label, + this.onTap, + this.hint, + this.labelStyle, + this.borderColor, + this.options = const >[], + super.key, + }); + /// The label that will be shown above the dropdown. final String? label; @@ -56,34 +70,22 @@ class ZdsDropdownList extends StatefulWidget { /// The border color of the dropdown. final Color? borderColor; - /// Constructs a [ZdsDropdownList]. - const ZdsDropdownList({ - this.onChange, - this.onReset, - this.value, - this.label, - this.onTap, - this.hint, - this.labelStyle, - this.borderColor, - this.options = const [], - super.key, - }); - @override ZdsDropdownListState createState() => ZdsDropdownListState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('label', label)); - properties.add(ObjectFlagProperty.has('onChange', onChange)); - properties.add(ObjectFlagProperty.has('onReset', onReset)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(IterableProperty>('options', options)); - properties.add(DiagnosticsProperty('value', value)); - properties.add(DiagnosticsProperty('labelStyle', labelStyle)); - properties.add(StringProperty('hint', hint)); - properties.add(ColorProperty('borderColor', borderColor)); + properties + ..add(StringProperty('label', label)) + ..add(ObjectFlagProperty.has('onChange', onChange)) + ..add(ObjectFlagProperty.has('onReset', onReset)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(IterableProperty>('options', options)) + ..add(DiagnosticsProperty('value', value)) + ..add(DiagnosticsProperty('labelStyle', labelStyle)) + ..add(StringProperty('hint', hint)) + ..add(ColorProperty('borderColor', borderColor)); } } @@ -101,7 +103,7 @@ class ZdsDropdownListState extends State> { void _setValue() { try { - _selectedItem = widget.options.where((element) => element.value == widget.value).first; + _selectedItem = widget.options.where((ZdsDropdownListItem element) => element.value == widget.value).first; _formFieldController.text = _selectedItem?.name ?? ''; } catch (e) { _selectedItem = null; @@ -132,7 +134,7 @@ class ZdsDropdownListState extends State> { @override Widget build(BuildContext context) { - final border = widget.borderColor != null + final ZdsInputBorder? border = widget.borderColor != null ? ZdsInputBorder( borderSide: BorderSide(color: widget.borderColor!), space: 2, @@ -140,16 +142,19 @@ class ZdsDropdownListState extends State> { ) : null; + final themeData = Theme.of(context); + final zetaColors = Zeta.of(context).colors; + return Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.label != null) ...[ + children: [ + if (widget.label != null) ...[ Text( widget.label!, style: widget.labelStyle ?? - Theme.of(context).textTheme.headlineSmall!.copyWith( - color: ZdsColors.greySwatch(context)[900], - ), + themeData.textTheme.headlineSmall?.copyWith( + color: zetaColors.textSubtle, + ), ), const SizedBox(height: 4), ], @@ -163,7 +168,7 @@ class ZdsDropdownListState extends State> { onTap: () => widget.onTap?.call(), child: DropdownButton2( value: _selectedItem?.value, - onMenuStateChange: (isOpen) => setState(() { + onMenuStateChange: (bool isOpen) => setState(() { _isOpen = isOpen; }), customButton: TextFormField( @@ -172,7 +177,7 @@ class ZdsDropdownListState extends State> { suffixPadding: const EdgeInsets.only(right: 8), suffixIcon: Icon( _isOpen ? ZdsIcons.chevron_up : ZdsIcons.chevron_down, - color: ZdsColors.greySwatch(context)[700], + color: zetaColors.iconSubtle, ), border: border, errorBorder: border, @@ -185,7 +190,7 @@ class ZdsDropdownListState extends State> { underline: const SizedBox(), items: widget.onTap == null ? widget.options.map( - (item) { + (ZdsDropdownListItem item) { return DropdownMenuItem( value: item.value, child: Text( @@ -195,11 +200,11 @@ class ZdsDropdownListState extends State> { ); }, ).toList() - : [], + : >[], menuItemStyleData: MenuItemStyleData( - selectedMenuItemBuilder: (context, child) { + selectedMenuItemBuilder: (BuildContext context, Widget child) { return ColoredBox( - color: Theme.of(context).colorScheme.secondary.withOpacity(0.1), + color: themeData.colorScheme.secondary.withOpacity(0.1), child: child, ); }, @@ -211,7 +216,8 @@ class ZdsDropdownListState extends State> { widget.onReset?.call(); } else if (value != null) { setState(() { - _selectedItem = widget.options.firstWhere((element) => element.value == value); + _selectedItem = + widget.options.firstWhere((ZdsDropdownListItem element) => element.value == value); }); _formFieldController.text = _selectedItem?.name ?? ''; widget.onChange?.call(value); diff --git a/lib/src/components/molecules/empty.dart b/lib/src/components/molecules/empty.dart index 953684f..69d47ce 100644 --- a/lib/src/components/molecules/empty.dart +++ b/lib/src/components/molecules/empty.dart @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Creates a message about no results being returned. /// /// This widget can be used to show a message for, when example, a search returns no results, or when no options are /// available. Typically, this widget is shown instead of the results list when the list is empty. class ZdsEmpty extends StatelessWidget { + /// Creates a message about no results being returned. + const ZdsEmpty({super.key, this.icon, this.message}); + /// The icon used for this message. /// /// Typically an [Icon]. @@ -17,21 +20,19 @@ class ZdsEmpty extends StatelessWidget { /// Typically a [Text]. final Widget? message; - /// Creates a message about no results being returned. - const ZdsEmpty({super.key, this.icon, this.message}); - @override Widget build(BuildContext context) { + final themeData = Theme.of(context); return Align( child: Column( mainAxisSize: MainAxisSize.min, - children: [ + children: [ // Icon if (!(context.isShortScreen() || context.isSmallScreen() || (context.isPhone() && context.isLandscape()))) ExcludeSemantics( child: IconTheme( data: IconThemeData( - color: Theme.of(context).colorScheme.secondary, + color: themeData.colorScheme.secondary, size: 72, ), child: icon ?? @@ -44,7 +45,7 @@ class ZdsEmpty extends StatelessWidget { // Message Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ + children: [ Flexible( child: MergeSemantics( child: message ?? @@ -53,7 +54,7 @@ class ZdsEmpty extends StatelessWidget { textAlign: TextAlign.center, ), ).textStyle( - Theme.of(context).textTheme.bodyLarge, + themeData.textTheme.displayMedium, overflow: TextOverflow.visible, textAlign: TextAlign.center, ), diff --git a/lib/src/components/molecules/expansion_tile.dart b/lib/src/components/molecules/expansion_tile.dart index 835c71d..de1f6f1 100644 --- a/lib/src/components/molecules/expansion_tile.dart +++ b/lib/src/components/molecules/expansion_tile.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_positional_boolean_parameters + import 'dart:async'; import 'dart:core'; @@ -5,7 +7,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/assets/icons.dart'; +import '../../utils/localizations/translation.dart'; +import '../../utils/tools/utils.dart'; +import '../atoms/card.dart'; /// Types of expansion tile enum ExpansionTileType { @@ -45,6 +50,52 @@ const Duration _kExpand = Duration(milliseconds: 200); /// ``` class ZdsExpansionTile extends StatefulWidget { + /// A tile that can be expanded and collapsed to reveal further information. + const ZdsExpansionTile({ + super.key, + required this.title, + required this.child, + this.subtitle, + this.bottom, + this.initiallyExpanded = false, + this.maintainState = true, + this.contentPadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 2), + this.titlePadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + this.onExpanded, + this.onCollapse, + this.onCollapsed, + this.showDivider = true, + this.expandWithIconOnly = false, + this.hideExpansionSemantics = false, + this.isExpandable = true, + this.titleColor = Colors.transparent, + }) : expansionTileType = ExpansionTileType.regular, + selected = false, + onSelected = null; + + /// A selectable tile that can be expanded and collapsed to reveal further information. + const ZdsExpansionTile.selectable({ + super.key, + required this.title, + required this.child, + this.subtitle, + this.bottom, + this.initiallyExpanded = false, + this.maintainState = true, + this.contentPadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 2), + this.titlePadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + this.onExpanded, + this.onCollapse, + this.onCollapsed, + this.selected = false, + this.onSelected, + this.showDivider = true, + this.expandWithIconOnly = false, + this.hideExpansionSemantics = false, + this.isExpandable = true, + this.titleColor = Colors.transparent, + }) : expansionTileType = ExpansionTileType.selectable; + /// The title of this expansion tile. This title will always be shown. /// /// Typically a [Text] widget. @@ -100,7 +151,6 @@ class ZdsExpansionTile extends StatefulWidget { final bool selected; /// A function called whenever an item is selected. - // ignore: avoid_positional_boolean_parameters final void Function(bool)? onSelected; /// Boolean to show divider between expansion tiles. @@ -130,75 +180,31 @@ class ZdsExpansionTile extends StatefulWidget { /// Determines the background color of the title part of the expansion tile. /// - /// Defaults to [ZdsColors.transparent]. + /// Defaults to [Colors.transparent]. final Color titleColor; - /// A tile that can be expanded and collapsed to reveal further information. - const ZdsExpansionTile({ - super.key, - required this.title, - required this.child, - this.subtitle, - this.bottom, - this.initiallyExpanded = false, - this.maintainState = true, - this.contentPadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 2), - this.titlePadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 16), - this.onExpanded, - this.onCollapse, - this.onCollapsed, - this.showDivider = true, - this.expandWithIconOnly = false, - this.hideExpansionSemantics = false, - this.isExpandable = true, - this.titleColor = ZdsColors.transparent, - }) : expansionTileType = ExpansionTileType.regular, - selected = false, - onSelected = null; - - /// A selectable tile that can be expanded and collapsed to reveal further information. - const ZdsExpansionTile.selectable({ - super.key, - required this.title, - required this.child, - this.subtitle, - this.bottom, - this.initiallyExpanded = false, - this.maintainState = true, - this.contentPadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 2), - this.titlePadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 16), - this.onExpanded, - this.onCollapse, - this.onCollapsed, - this.selected = false, - this.onSelected, - this.showDivider = true, - this.expandWithIconOnly = false, - this.hideExpansionSemantics = false, - this.isExpandable = true, - this.titleColor = ZdsColors.transparent, - }) : expansionTileType = ExpansionTileType.selectable; - @override ZdsExpansionTileState createState() => ZdsExpansionTileState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('initiallyExpanded', initiallyExpanded)); - properties.add(DiagnosticsProperty('maintainState', maintainState)); - properties.add(DiagnosticsProperty('contentPadding', contentPadding)); - properties.add(DiagnosticsProperty('titlePadding', titlePadding)); - properties.add(ObjectFlagProperty.has('onExpanded', onExpanded)); - properties.add(ObjectFlagProperty.has('onCollapse', onCollapse)); - properties.add(ObjectFlagProperty.has('onCollapsed', onCollapsed)); - properties.add(DiagnosticsProperty('selected', selected)); - properties.add(ObjectFlagProperty.has('onSelected', onSelected)); - properties.add(DiagnosticsProperty('showDivider', showDivider)); - properties.add(DiagnosticsProperty('expandWithIconOnly', expandWithIconOnly)); - properties.add(DiagnosticsProperty('hideExpansionSemantics', hideExpansionSemantics)); - properties.add(DiagnosticsProperty('isExpandable', isExpandable)); - properties.add(EnumProperty('expansionTileType', expansionTileType)); - properties.add(ColorProperty('titleColor', titleColor)); + properties + ..add(DiagnosticsProperty('initiallyExpanded', initiallyExpanded)) + ..add(DiagnosticsProperty('maintainState', maintainState)) + ..add(DiagnosticsProperty('contentPadding', contentPadding)) + ..add(DiagnosticsProperty('titlePadding', titlePadding)) + ..add(ObjectFlagProperty.has('onExpanded', onExpanded)) + ..add(ObjectFlagProperty.has('onCollapse', onCollapse)) + ..add(ObjectFlagProperty.has('onCollapsed', onCollapsed)) + ..add(DiagnosticsProperty('selected', selected)) + ..add(DiagnosticsProperty('showDivider', showDivider)) + ..add(DiagnosticsProperty('expandWithIconOnly', expandWithIconOnly)) + ..add(DiagnosticsProperty('hideExpansionSemantics', hideExpansionSemantics)) + ..add(DiagnosticsProperty('isExpandable', isExpandable)) + ..add(EnumProperty('expansionTileType', expansionTileType)) + ..add(ColorProperty('titleColor', titleColor)) + ..add(ObjectFlagProperty.has('onSelected', onSelected)); } } @@ -304,28 +310,31 @@ class ZdsExpansionTileState extends State with SingleTickerPro Widget build(BuildContext context) { final bool closed = !_isExpanded && _controller.isDismissed; final bool shouldRemoveChildren = closed && !widget.maintainState; + final zeta = Zeta.of(context); + return AnimatedBuilder( animation: _controller.view, builder: (BuildContext context, Widget? child) { - final card = context.findAncestorWidgetOfExactType(); - final chevronIcon = IconButton( + final ZdsCard? card = context.findAncestorWidgetOfExactType(); + final IconButton chevronIcon = IconButton( onPressed: toggle, icon: RotationTransition( turns: _iconTurns, child: Icon( widget.expansionTileType == ExpansionTileType.regular ? ZdsIcons.chevron_down : ZdsIcons.chevron_right, - color: ZdsColors.greySwatch(context)[800], + color: zeta.colors.iconDefault, size: 24, ), ), ); + final themeData = Theme.of(context); return Stack( clipBehavior: Clip.none, - children: [ + children: [ Column( mainAxisSize: MainAxisSize.min, - children: [ + children: [ Material( color: widget.titleColor, child: Semantics( @@ -337,13 +346,13 @@ class ZdsExpansionTileState extends State with SingleTickerPro ? _toggleSelect : toggle, child: Column( - children: [ + children: [ Padding( padding: widget.expansionTileType == ExpansionTileType.selectable ? const EdgeInsets.fromLTRB(8, 4, 20, 4) : widget.titlePadding, child: Row( - children: [ + children: [ if (widget.expansionTileType == ExpansionTileType.selectable) Semantics( onTapHint: _isExpanded @@ -354,22 +363,20 @@ class ZdsExpansionTileState extends State with SingleTickerPro Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ DefaultTextStyle( - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: ZetaColors.of(context).textDefault), + style: safeTextStyle(themeData.textTheme.bodyLarge) + .copyWith(color: zeta.colors.textDefault), maxLines: 1, overflow: TextOverflow.ellipsis, child: widget.title, ), - if (widget.subtitle != null) ...[ + if (widget.subtitle != null) ...[ const SizedBox(height: 5), DefaultTextStyle( - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ZetaColors.of(context).textSubtle, - ), + style: themeData.textTheme.bodySmall!.copyWith( + color: zeta.colors.textSubtle, + ), child: widget.subtitle!, ), ], @@ -385,7 +392,7 @@ class ZdsExpansionTileState extends State with SingleTickerPro child: widget.expandWithIconOnly ? chevronIcon : IconTheme( - data: IconThemeData(color: ZetaColors.of(context).textSubtle, size: 24), + data: IconThemeData(color: zeta.colors.iconSubtle, size: 24), child: RotationTransition( turns: _iconTurns, child: const Icon(ZdsIcons.chevron_down), @@ -395,7 +402,7 @@ class ZdsExpansionTileState extends State with SingleTickerPro if (widget.selected) IconTheme( data: IconThemeData( - color: Theme.of(context).colorScheme.secondary, + color: themeData.colorScheme.secondary, size: 24, ), child: const Icon(ZdsIcons.check), @@ -425,7 +432,7 @@ class ZdsExpansionTileState extends State with SingleTickerPro right: 0, child: Container( height: 1, - color: card != null ? ZdsColors.lightGrey.withOpacity(0.5) : ZdsColors.transparent, + color: card != null ? zeta.colors.borderSubtle : Colors.transparent, ), ), ], diff --git a/lib/src/components/molecules/fields_list_tile.dart b/lib/src/components/molecules/fields_list_tile.dart index 608063a..239b115 100644 --- a/lib/src/components/molecules/fields_list_tile.dart +++ b/lib/src/components/molecules/fields_list_tile.dart @@ -1,7 +1,11 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/tools/modifiers.dart'; +import '../../utils/tools/utils.dart'; +import '../atoms/card.dart'; +import '../organisms/properties_list.dart'; /// A tile showing a list of properties with their respective values. /// @@ -30,6 +34,22 @@ import '../../../zds_flutter.dart'; /// * [ZdsPropertiesList], another way to show table-like data. /// * [TileField], which defines the fields. class ZdsFieldsListTile extends StatelessWidget { + /// Creates a tile showing a list of properties with their respective values. + + const ZdsFieldsListTile({ + super.key, + this.title, + this.fields, + this.fieldsStartTextStyle, + this.fieldsEndTextStyle, + this.data, + this.footnote, + this.onTap, + this.shrink = true, + this.startFieldFlexFactor, + this.cardPadding = const EdgeInsets.symmetric(horizontal: 14, vertical: 18), + }); + /// The title, shown at the top of this tile. /// /// Typically a [Text]. @@ -42,7 +62,7 @@ class ZdsFieldsListTile extends StatelessWidget { /// The textStyle used for the starting elements of each field. /// - /// Defaults to [TextTheme.titleSmall] with [ZdsColors.blueGrey] color. + /// Defaults to [TextTheme.titleSmall] with [$color.zeta.text.default] color. final TextStyle? fieldsStartTextStyle; /// The textStyle used for the end elements of each field. @@ -78,57 +98,43 @@ class ZdsFieldsListTile extends StatelessWidget { /// Defaults to EdgeInsets.symmetric(horizontal: 14, vertical: 18). final EdgeInsets cardPadding; - /// Creates a tile showing a list of properties with their respective values. - const ZdsFieldsListTile({ - super.key, - this.title, - this.fields, - this.fieldsStartTextStyle, - this.fieldsEndTextStyle, - this.data, - this.footnote, - this.onTap, - this.shrink = true, - this.startFieldFlexFactor, - this.cardPadding = const EdgeInsets.symmetric(horizontal: 14, vertical: 18), - }); - @override Widget build(BuildContext context) { + final themeData = Theme.of(context); return ZdsCard( padding: cardPadding, onTap: onTap != null ? () => onTap!.call(data) : null, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ + children: [ if (title != null) DefaultTextStyle( - style: Theme.of(context).textTheme.bodyLarge!, + style: themeData.textTheme.bodyLarge!, child: title!, ).space(), if (fields != null) ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (_, index) => buildDetailRow( + itemBuilder: (_, int index) => buildDetailRow( context: context, field: fields![index], fieldsStartDefaultStyle: fieldsStartTextStyle, fieldsEndDefaultStyle: fieldsEndTextStyle, startFieldFlexFactor: startFieldFlexFactor, ), - separatorBuilder: (_, index) => + separatorBuilder: (_, int index) => SizedBox(height: fields?[index].start != null && fields?[index].end != null ? (shrink ? 10 : 18) : 0), itemCount: fields!.length, ), if (footnote != null) Column( - children: [ + children: [ const SizedBox(height: 8), DefaultTextStyle( - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: ZdsColors.greySwatch(context)[900], - ), + style: safeTextStyle(themeData.textTheme.bodyMedium).copyWith( + color: Zeta.of(context).colors.textDisabled, + ), child: footnote!, ), ], @@ -141,14 +147,15 @@ class ZdsFieldsListTile extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IterableProperty('fields', fields)); - properties.add(DiagnosticsProperty('fieldsStartTextStyle', fieldsStartTextStyle)); - properties.add(DiagnosticsProperty('fieldsEndTextStyle', fieldsEndTextStyle)); - properties.add(DiagnosticsProperty('data', data)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(DiagnosticsProperty('shrink', shrink)); - properties.add(IntProperty('startFieldFlexFactor', startFieldFlexFactor)); - properties.add(DiagnosticsProperty('cardPadding', cardPadding)); + properties + ..add(IterableProperty('fields', fields)) + ..add(DiagnosticsProperty('fieldsStartTextStyle', fieldsStartTextStyle)) + ..add(DiagnosticsProperty('fieldsEndTextStyle', fieldsEndTextStyle)) + ..add(DiagnosticsProperty('data', data)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(DiagnosticsProperty('shrink', shrink)) + ..add(IntProperty('startFieldFlexFactor', startFieldFlexFactor)) + ..add(DiagnosticsProperty('cardPadding', cardPadding)); } } @@ -160,14 +167,17 @@ extension _UIBuilder on ZdsFieldsListTile { TextStyle? fieldsEndDefaultStyle, int? startFieldFlexFactor, }) { + final themeData = Theme.of(context); return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ if (field.start != null) DefaultTextStyle( - style: - fieldsStartDefaultStyle ?? Theme.of(context).textTheme.titleSmall!.copyWith(color: ZdsColors.blueGrey), + style: fieldsStartDefaultStyle ?? + safeTextStyle(themeData.textTheme.titleSmall).copyWith( + color: Zeta.of(context).colors.textSubtle, + ), textAlign: TextAlign.start, child: Flexible(flex: startFieldFlexFactor ?? 0, child: field.start!), ) @@ -176,7 +186,7 @@ extension _UIBuilder on ZdsFieldsListTile { const SizedBox(width: 12), if (field.end != null) DefaultTextStyle( - style: fieldsEndDefaultStyle ?? Theme.of(context).textTheme.bodyMedium!, + style: fieldsEndDefaultStyle ?? safeTextStyle(themeData.textTheme.bodyMedium), textAlign: TextAlign.end, child: Flexible(child: field.end!), ), @@ -187,15 +197,15 @@ extension _UIBuilder on ZdsFieldsListTile { /// Pairs of data used with [ZdsFieldsListTile]. class TileField { - /// Start widget of the data. - final Widget? start; - - /// End widget of the data. - final Widget? end; - /// Constructs a [TileField]. const TileField({ this.start, this.end, }); + + /// Start widget of the data. + final Widget? start; + + /// End widget of the data. + final Widget? end; } diff --git a/lib/src/components/molecules/icon_badge_widget.dart b/lib/src/components/molecules/icon_badge_widget.dart index 638526d..89341b9 100644 --- a/lib/src/components/molecules/icon_badge_widget.dart +++ b/lib/src/components/molecules/icon_badge_widget.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Shows an icon with an unread badge. /// @@ -15,6 +15,30 @@ import '../../../zds_flutter.dart'; /// * [UnreadBadge], used to show the unread badge in this /// * [ZdsNavItem], where this widget can be used as the icon. class IconWithBadge extends StatelessWidget { + /// Displays an icon with an optional unread badge if the [unread] parameter is given. The optional [semanticsLabel] + /// parameter is used by the unreadBadge child. + /// + /// No badge will show if [unread] is 0. + /// + /// All parameters except [semanticsLabel] must not be null. + const IconWithBadge( + this.icon, { + super.key, + this.color, + this.fill, + this.grade, + this.maximumDigits = 3, + this.opticalSize, + this.semanticLabel, + this.semanticsLabel, + this.shadows, + this.size = 24, + this.textDirection, + this.unread = 0, + this.weight, + this.iconContainerColor, + }) : assert(maximumDigits >= 1, 'maximumDigits must be greater than or equal to 1.'); + /// The number to show in the badge. If it's equal to 0, only the icon will be shown and no badge will show. /// /// Defaults to 0. @@ -187,38 +211,14 @@ class IconWithBadge extends StatelessWidget { /// This color is later used to draw a border around the [UnreadBadge]. final Color? iconContainerColor; - /// Displays an icon with an optional unread badge if the [unread] parameter is given. The optional [semanticsLabel] - /// parameter is used by the unreadBadge child. - /// - /// No badge will show if [unread] is 0. - /// - /// All parameters except [semanticsLabel] must not be null. - const IconWithBadge( - this.icon, { - super.key, - this.color, - this.fill, - this.grade, - this.maximumDigits = 3, - this.opticalSize, - this.semanticLabel, - this.semanticsLabel, - this.shadows, - this.size = 24, - this.textDirection, - this.unread = 0, - this.weight, - this.iconContainerColor, - }) : assert(maximumDigits >= 1, 'maximumDigits must be greater than or equal to 1.'); - @override Widget build(BuildContext context) { - final badgeSize = size * 0.6; + final double badgeSize = size * 0.6; return Center( child: Stack( alignment: Alignment.center, clipBehavior: Clip.none, - children: [ + children: [ Icon( icon, size: size, diff --git a/lib/src/components/molecules/information_bar.dart b/lib/src/components/molecules/information_bar.dart index 3cf814c..85af01b 100644 --- a/lib/src/components/molecules/information_bar.dart +++ b/lib/src/components/molecules/information_bar.dart @@ -2,15 +2,48 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/tools/modifiers.dart'; + +/// Sets a [ZdsInformationBar]'s icon and background colors. +enum ZdsInformationBarTheme { + /// Default theme, used for non-status information, like timestamps, quantity information... + neutral, + + /// Theme used for positive status, like completed, approved, achieved... + positive, + + /// Theme used for when the status is not final yet, like pending, in progress, scheduled... + inProgress, + + /// Theme used for negative status, like declined, removed, failed... + negative +} /// A bar used to display status information. /// /// Typically used at the top of the page, below the appbar, to display status information. class ZdsInformationBar extends StatelessWidget { + /// Creates a bar used to display status information. + const ZdsInformationBar({ + super.key, + this.color = ZdsInformationBarTheme.neutral, + this.icon, + this.label, + this.customBackground, + this.customForeground, + this.zetaColorSwatch, + }); + + /// The color theme used for the bar's background and the [icon]'s color. + /// + /// Defaults to [ZdsInformationBarTheme.neutral]. + /// + /// Will be deprecated and replaced with ZetaColorSwatch in future release. + final ZdsInformationBarTheme color; + /// The icon shown before the [label]. /// - /// The color used will be determined by [zetaColorSwatch]. + /// The color used will be determined by [color]. final IconData? icon; /// The label shown after the [icon]. @@ -18,16 +51,12 @@ class ZdsInformationBar extends StatelessWidget { /// Custom foreground color. /// - /// Overrides [zetaColorSwatch]. - /// - /// Will be deprecated and replaced with ZetaColorSwatch in future release. + /// Overrides [color]. final Color? customForeground; /// Custom background color. /// - /// Overrides [zetaColorSwatch]. - /// - /// Will be deprecated and replaced with ZetaColorSwatch in future release. + /// Overrides [color]. final Color? customBackground; /// Color for the information bar. @@ -35,27 +64,17 @@ class ZdsInformationBar extends StatelessWidget { /// * Background: `color.surface`. /// * Icon: `color.icon`. /// * Text: default text color. - /// - /// Defaults to primary color swatch. final ZetaColorSwatch? zetaColorSwatch; - /// Creates a bar used to display status information. - const ZdsInformationBar({ - super.key, - this.icon, - this.label, - this.customBackground, - this.customForeground, - this.zetaColorSwatch, - }); - @override Widget build(BuildContext context) { - final Color bg = zetaColorSwatch?.shade20 ?? customBackground ?? ZetaColors.of(context).primary.surface; + final zeta = Zeta.of(context); + final Color backgroundColor = customBackground ?? zetaColorSwatch?.shade20 ?? _getBarColor(color, zeta.colors); + final Color foregroundColor = customForeground ?? zetaColorSwatch ?? _getIconColor(color, zeta.colors); return Container( height: 42, width: double.maxFinite, - color: bg, + color: backgroundColor, child: SafeArea( top: false, bottom: false, @@ -65,7 +84,7 @@ class ZdsInformationBar extends StatelessWidget { if (icon != null) Icon( icon, - color: zetaColorSwatch?.icon ?? customForeground ?? ZetaColors.of(context).primary.icon, + color: foregroundColor, size: 24, ).paddingOnly(right: 8), if (label != null) @@ -73,8 +92,7 @@ class ZdsInformationBar extends StatelessWidget { child: Text( label!, overflow: TextOverflow.ellipsis, - style: - Theme.of(context).textTheme.titleSmall?.copyWith(color: ZetaColors.computeForeground(input: bg)), + style: Theme.of(context).textTheme.titleSmall, ), ), ], @@ -86,11 +104,38 @@ class ZdsInformationBar extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); + properties + ..add(EnumProperty('color', color)) + ..add(DiagnosticsProperty('icon', icon)) + ..add(StringProperty('label', label)) + ..add(ColorProperty('customForeground', customForeground)) + ..add(ColorProperty('customBackground', customBackground)) + ..add(ColorProperty('zetaColorSwatch', zetaColorSwatch)); + } +} + +Color _getBarColor(ZdsInformationBarTheme color, ZetaColors colors) { + switch (color) { + case ZdsInformationBarTheme.neutral: + return colors.cool.surface; + case ZdsInformationBarTheme.positive: + return colors.green.surface; + case ZdsInformationBarTheme.inProgress: + return colors.secondary.surface; + case ZdsInformationBarTheme.negative: + return colors.negative.surface; + } +} - properties.add(DiagnosticsProperty('icon', icon)); - properties.add(StringProperty('label', label)); - properties.add(ColorProperty('customForeground', customForeground)); - properties.add(ColorProperty('customBackground', customBackground)); - properties.add(ColorProperty('zetaColorSwatch', zetaColorSwatch)); +Color _getIconColor(ZdsInformationBarTheme color, ZetaColors colors) { + switch (color) { + case ZdsInformationBarTheme.neutral: + return colors.cool.icon; + case ZdsInformationBarTheme.positive: + return colors.green.icon; + case ZdsInformationBarTheme.inProgress: + return colors.secondary.icon; + case ZdsInformationBarTheme.negative: + return colors.negative.icon; } } diff --git a/lib/src/components/molecules/input_dialog.dart b/lib/src/components/molecules/input_dialog.dart index 500ce78..7b1c5dd 100644 --- a/lib/src/components/molecules/input_dialog.dart +++ b/lib/src/components/molecules/input_dialog.dart @@ -1,8 +1,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/localizations.dart'; +import '../../utils/theme/input_border.dart'; +import '../atoms/button.dart'; +import '../organisms/modal.dart'; /// A dialog with a textfield and built-in validation. /// @@ -34,6 +38,22 @@ import '../../../zds_flutter.dart'; /// /// * [ZdsModal], to create a general purpose dialog. class ZdsInputDialog extends StatefulWidget { + /// A dialog used to retrieve 1 String value with built-in validation. + const ZdsInputDialog({ + required this.primaryAction, + super.key, + this.title, + this.labelText, + this.hint, + this.initialText, + this.secondaryAction, + this.inputAction = TextInputAction.done, + this.autoFocus = true, + this.inputFormatters, + this.onValidate, + this.characterCount, + }); + /// The title of this dialog, shown at the top. final String? title; @@ -83,38 +103,24 @@ class ZdsInputDialog extends StatefulWidget { /// String means validation failed, with said String being the error text. final Future Function(String text)? onValidate; - /// A dialog used to retrieve 1 String value with built-in validation. - const ZdsInputDialog({ - required this.primaryAction, - super.key, - this.title, - this.labelText, - this.hint, - this.initialText, - this.secondaryAction, - this.inputAction = TextInputAction.done, - this.autoFocus = true, - this.inputFormatters, - this.onValidate, - this.characterCount, - }); - @override ZdsInputDialogState createState() => ZdsInputDialogState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('title', title)); - properties.add(StringProperty('labelText', labelText)); - properties.add(StringProperty('hint', hint)); - properties.add(IntProperty('characterCount', characterCount)); - properties.add(StringProperty('primaryAction', primaryAction)); - properties.add(StringProperty('secondaryAction', secondaryAction)); - properties.add(EnumProperty('inputAction', inputAction)); - properties.add(DiagnosticsProperty('autoFocus', autoFocus)); - properties.add(StringProperty('initialText', initialText)); - properties.add(IterableProperty('inputFormatters', inputFormatters)); - properties.add(ObjectFlagProperty Function(String text)?>.has('onValidate', onValidate)); + properties + ..add(StringProperty('title', title)) + ..add(StringProperty('labelText', labelText)) + ..add(StringProperty('hint', hint)) + ..add(IntProperty('characterCount', characterCount)) + ..add(StringProperty('primaryAction', primaryAction)) + ..add(StringProperty('secondaryAction', secondaryAction)) + ..add(EnumProperty('inputAction', inputAction)) + ..add(DiagnosticsProperty('autoFocus', autoFocus)) + ..add(StringProperty('initialText', initialText)) + ..add(IterableProperty('inputFormatters', inputFormatters)) + ..add(ObjectFlagProperty Function(String text)?>.has('onValidate', onValidate)); } } @@ -123,6 +129,7 @@ class ZdsInputDialogState extends State { late final TextEditingController _controller = TextEditingController(); String? _error; int? _characterLeftCount; + final FocusNode _focusNode = FocusNode(); @override void initState() { @@ -142,7 +149,7 @@ class ZdsInputDialogState extends State { @override Widget build(BuildContext context) { final theme = Theme.of(context); - + final zetaColors = Zeta.of(context).colors; return Dialog( child: Container( width: double.infinity, @@ -150,37 +157,52 @@ class ZdsInputDialogState extends State { child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (widget.title != null) Text(widget.title!, style: theme.textTheme.headlineMedium), + children: [ + if (widget.title != null) + Text( + widget.title!, + style: theme.textTheme.displaySmall?.copyWith( + color: zetaColors.textDefault, + ), + ), Padding( padding: const EdgeInsets.only(top: 8, bottom: 30), child: Row( children: [ Expanded( - child: TextFormField( - maxLength: widget.characterCount, - autofocus: widget.autoFocus, - textInputAction: widget.inputAction, - controller: _controller, - inputFormatters: widget.inputFormatters, - onChanged: (value) async { - await _validateText(); - }, - onFieldSubmitted: (_) async { - final error = await _validateText(); - if ((error?.isEmpty ?? true) && mounted) { - await Navigator.maybePop(context, _controller.text); - } - }, - decoration: ZdsInputDecoration( - labelText: widget.labelText, - counterText: widget.characterCount != null && _error == null - ? ComponentStrings.of(context) - .get('CHAR_LEFT', 'Characters Left {0}', args: ['$_characterLeftCount']) - : null, - hintText: widget.hint, - errorText: _error, - errorStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(color: ZdsColors.red), + child: Semantics( + textField: true, + onTap: _focusNode.requestFocus, + excludeSemantics: true, + label: _controller.text.isNotEmpty ? _controller.text : widget.hint, + child: TextFormField( + maxLength: widget.characterCount, + autofocus: widget.autoFocus, + textInputAction: widget.inputAction, + controller: _controller, + focusNode: _focusNode, + inputFormatters: widget.inputFormatters, + onChanged: (String value) async { + await _validateText(); + }, + onFieldSubmitted: (_) async { + final String? error = await _validateText(); + if ((error?.isEmpty ?? true) && mounted) { + await Navigator.maybePop(context, _controller.text); + } + }, + decoration: ZdsInputDecoration( + labelText: widget.labelText, + counterText: widget.characterCount != null && _error == null + ? ComponentStrings.of(context) + .get('CHAR_LEFT', 'Characters Left {0}', args: ['$_characterLeftCount']) + : null, + hintText: widget.hint, + errorText: _error, + errorStyle: theme.textTheme.bodyMedium?.copyWith( + color: zetaColors.error, + ), + ), ), ), ), @@ -189,29 +211,34 @@ class ZdsInputDialogState extends State { ), ConstrainedBox( constraints: const BoxConstraints(maxHeight: 48), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (widget.secondaryAction != null) - ZdsButton.muted( - key: const Key('secondary_button'), - onTap: () async => Navigator.maybePop(context), - child: Text(widget.secondaryAction!), - ), - if (widget.secondaryAction != null) const SizedBox(width: 8), - ZdsButton.filled( - key: const Key('primary_button'), - onTap: _error == null - ? () async { - final error = await _validateText(); - if ((error?.isEmpty ?? true) && mounted) { - await Navigator.maybePop(context, _controller.text); + child: FittedBox( + alignment: Alignment.centerRight, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (widget.secondaryAction != null) + ZdsButton.muted( + semanticLabel: widget.secondaryAction, + key: const Key('secondary_button'), + onTap: () async => Navigator.maybePop(context), + child: Text(widget.secondaryAction!), + ), + if (widget.secondaryAction != null) const SizedBox(width: 8), + ZdsButton.filled( + semanticLabel: widget.primaryAction, + key: const Key('primary_button'), + onTap: _error == null + ? () async { + final String? error = await _validateText(); + if ((error?.isEmpty ?? true) && mounted) { + await Navigator.maybePop(context, _controller.text); + } } - } - : null, - child: Text(widget.primaryAction), - ), - ], + : null, + child: Text(widget.primaryAction), + ), + ], + ), ), ), ], @@ -221,7 +248,7 @@ class ZdsInputDialogState extends State { } Future _validateText() async { - final error = await widget.onValidate?.call(_controller.text); + final String? error = await widget.onValidate?.call(_controller.text); if (mounted) { setState(() { _error = error; diff --git a/lib/src/components/molecules/list.dart b/lib/src/components/molecules/list.dart index dcdb12f..e83f596 100644 --- a/lib/src/components/molecules/list.dart +++ b/lib/src/components/molecules/list.dart @@ -1,13 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; import '../../utils/tools/measure.dart'; -const _emptyChildLength = 30; +const int _emptyChildLength = 30; final List _emptyChildren = - List.generate(_emptyChildLength, (_) => _emptyChild).divide(const Divider()).toList(); + List.generate(_emptyChildLength, (_) => _emptyChild).divide(const Divider()).toList(); const Widget _emptyChild = SizedBox(height: 60, width: double.infinity); @@ -19,13 +19,6 @@ Widget _emptyBuilder(_, __) => _emptyChild; /// /// * [ListView]. class ZdsList extends ListView { - /// {@template ZdsList.showEmpty} - /// Whether to show an empty list with a divider if the `children` list is empty. - /// - /// Defaults to false. - /// {@endtemplate} - final bool showEmpty; - /// Creates a [ZdsList]. ZdsList({ super.key, @@ -56,6 +49,8 @@ class ZdsList extends ListView { children: showEmpty && children.isEmpty ? _emptyChildren : children, ); + // TODO(thelukewalton): Add prop for seperated list with divider + /// Creates a ZdsList with an itemBuilder. /// /// Extends [ListView.builder] with Zds styling and behavior. @@ -105,6 +100,13 @@ class ZdsList extends ListView { return const SizedBox.shrink(); }, ); + + /// {@template ZdsList.showEmpty} + /// Whether to show an empty list with a divider if the `children` list is empty. + /// + /// Defaults to false. + /// {@endtemplate} + final bool showEmpty; @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -133,22 +135,21 @@ class ZdsHorizontalList extends _ZdsHorizontalList { } class _ZdsHorizontalList extends StatelessWidget { + const _ZdsHorizontalList({super.key, this.delegate, this.caption, this.isReducedHeight = false}); final Widget? caption; final _ZdsHorizontalChildDelegate? delegate; final bool isReducedHeight; - const _ZdsHorizontalList({super.key, this.delegate, this.caption, this.isReducedHeight = false}); - @override Widget build(BuildContext context) { - final firstItem = delegate!.build(context, 0); + final Widget firstItem = delegate!.build(context, 0); return MeasureSize( child: firstItem, - builder: (context, size) { + builder: (BuildContext context, Size size) { return Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ DefaultTextStyle( style: Theme.of(context).textTheme.displayMedium!, child: caption != null ? caption!.paddingOnly(top: 20, left: 20, right: 20) : const SizedBox(), @@ -159,7 +160,7 @@ class _ZdsHorizontalList extends StatelessWidget { child: CustomScrollView( shrinkWrap: true, scrollDirection: Axis.horizontal, - slivers: [ + slivers: [ SliverPadding( padding: const EdgeInsets.all(10), sliver: SliverList( @@ -188,9 +189,8 @@ class _ZdsHorizontalList extends StatelessWidget { } class _ZdsHorizontalListChildrenDelegate extends _ZdsHorizontalChildDelegate { - final List? children; - _ZdsHorizontalListChildrenDelegate(this.children) : super(); + final List? children; @override int get estimatedChildCount => children!.length; @@ -202,11 +202,10 @@ class _ZdsHorizontalListChildrenDelegate extends _ZdsHorizontalChildDelegate { } class _ZdsHorizontalListBuilderDelegate extends _ZdsHorizontalChildDelegate { + _ZdsHorizontalListBuilderDelegate(this.builder, this.itemCount) : super(); final int? itemCount; final BuilderCallback? builder; - _ZdsHorizontalListBuilderDelegate(this.builder, this.itemCount) : super(); - @override int? get estimatedChildCount => itemCount; diff --git a/lib/src/components/molecules/list_tile_wrapper.dart b/lib/src/components/molecules/list_tile_wrapper.dart index 4817d0e..25db0e7 100644 --- a/lib/src/components/molecules/list_tile_wrapper.dart +++ b/lib/src/components/molecules/list_tile_wrapper.dart @@ -1,11 +1,65 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; -/// Component to add additional styling to a ZdsListTile. +import '../../utils/theme.dart'; +import '../atoms/border_clipper.dart'; +import '../organisms/list_tile.dart'; + +/// This Widget takes in the following parameters: +/// +/// [key] : Key to assign to the widget. +/// +/// [child] : The Widget that will be wrapped by [ZdsListTileWrapper]. Typically a [ZdsListTile] for the styling to be applied to. +/// +/// [top] : A boolean value to indicate whether to add custom styling to the top part of the widget. Default value is `false`. +/// +/// [bottom] : A boolean value to indicate whether to add custom styling to the bottom part of the widget. Default value is `false`. +/// +/// [dividers] : A boolean value to indicate whether to add divider below the child. Default value is `true`. +/// +/// Here is an example of how to use this class: +/// +/// ```dart +/// static const tileCount = 6; +/// +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// body: ListView.separated( +/// itemCount: tileCount, +/// padding: const EdgeInsets.all(14), +/// separatorBuilder: (context, index) => const Divider(), +/// itemBuilder: (context, index) { +/// return ZdsListTileWrapper( +/// top: index == 0, +/// bottom: index == (tileCount - 1), +/// child: ZdsListTile( +/// title: Text('Title $index'), +/// subtitle: Text('Subtitle $index'), +/// ), +/// ); +/// }, +/// ), +/// ); +/// } +/// ``` +/// +/// Note: You should specify [key] value if you need to reference this particular widget +/// later on, you can leave it otherwise. /// -/// Removes the gap between ZdsTiles when used in a list and adds dividing lines between the tiles and rounds the corners. class ZdsListTileWrapper extends StatelessWidget { + /// Constructs a [ZdsListTileWrapper]. + const ZdsListTileWrapper({ + super.key, + required this.child, + this.top = false, + this.bottom = false, + this.dividers = true, + this.backgroundColor, + }); + + /// The Widget that will be wrapped by `ZdsListTileWrapper`. + /// /// Typically a ZdsListTile for the styling to be applied to. final Widget child; @@ -19,52 +73,114 @@ class ZdsListTileWrapper extends StatelessWidget { /// Defaults to false. final bool bottom; - /// Constructs a [ZdsListTileWrapper]. - const ZdsListTileWrapper({required this.child, super.key, this.top = false, this.bottom = false}); + /// Whether the divider should be added at the bottom of the tile. + /// + /// Defaults to true. + final bool dividers; + + /// Background Color of the wrapper + /// + /// Useful when child is [ListTile] which does not have any inherent background color + /// + /// When not given then defaulted to the [ColorScheme.surface] + final Color? backgroundColor; + + static const _topClipper = ZdsBorderClipper(top: -4, bottom: 0, left: -4, right: -4); + static const _bottomClipper = ZdsBorderClipper(top: 0, bottom: -4, left: -4, right: -4); + static const _middleClipper = ZdsBorderClipper(top: 0, bottom: 0, left: -4, right: -4); @override Widget build(BuildContext context) { - final ZetaColors colors = ZetaColors.of(context); - return ClipRect( - clipper: _PaddingRect( - const EdgeInsets.symmetric(horizontal: 10).copyWith(top: top ? 10 : 0, bottom: bottom ? 10 : 0), - ), - child: Padding( - padding: EdgeInsets.only(top: top ? 10 : 0, bottom: bottom ? 10 : 0), - child: DecoratedBox( - decoration: BoxDecoration( - border: Border( - top: top ? BorderSide.none : BorderSide(color: colors.cool.shade40), - bottom: bottom ? BorderSide.none : BorderSide(color: colors.cool.shade40), - ), - boxShadow: [ - BoxShadow( - blurRadius: 4, - color: colors.shadow, - ), - ], - ), - child: Material( - clipBehavior: Clip.antiAlias, - borderRadius: BorderRadius.only( - topLeft: top ? const Radius.circular(6) : Radius.zero, - topRight: top ? const Radius.circular(6) : Radius.zero, - bottomLeft: bottom ? const Radius.circular(6) : Radius.zero, - bottomRight: bottom ? const Radius.circular(6) : Radius.zero, - ), - color: ZetaColors.of(context).background, - child: DecoratedBox( - decoration: BoxDecoration( - border: Border( - top: top ? BorderSide.none : BorderSide(color: Theme.of(context).dividerColor), - ), - ), - child: child, - ), - ), - ), + // Gets the theme data + final themeData = Theme.of(context); + + // Gets card theme data + final cardTheme = themeData.cardTheme; + + // Regular border radius + BorderRadius borderRadius = BorderRadius.circular(kZdsCardRadius); + + // Check if the card shape is Rounded Rectangle and accordingly set its borderRadius + if (cardTheme.shape != null && cardTheme.shape is RoundedRectangleBorder) { + final cardShape = cardTheme.shape as RoundedRectangleBorder?; + if (cardShape != null && cardShape.borderRadius is BorderRadius) { + borderRadius = cardShape.borderRadius as BorderRadius; + } + } + + // Custom border radius and box shadow + BorderRadius customBorderRadius; + + // Shadow color + final shadowColor = cardTheme.shadowColor ?? Colors.black38; + List customBoxShadow; + + // Depending on the top and bottom properties, set customBorderRadius and customBoxShadow + if (top && bottom) { + customBorderRadius = borderRadius; + customBoxShadow = [BoxShadow(blurRadius: 1, color: shadowColor)]; + } else if (top) { + customBorderRadius = BorderRadius.only( + topLeft: borderRadius.topLeft, + topRight: borderRadius.topRight, + ); + customBoxShadow = [ + BoxShadow(color: shadowColor, blurRadius: 0.5, offset: const Offset(0, -1)), + BoxShadow(color: shadowColor, blurRadius: 0.5, offset: const Offset(1, 0)), + BoxShadow(color: shadowColor, blurRadius: 0.5, offset: const Offset(-1, 0)), + ]; + } else if (bottom) { + customBorderRadius = BorderRadius.only( + bottomLeft: borderRadius.bottomLeft, + bottomRight: borderRadius.bottomRight, + ); + customBoxShadow = [ + BoxShadow(color: shadowColor, blurRadius: 0.5, offset: const Offset(0, 1)), + BoxShadow(color: shadowColor, blurRadius: 0.5, offset: const Offset(1, 0)), + BoxShadow(color: shadowColor, blurRadius: 0.5, offset: const Offset(-1, 0)), + ]; + } else { + customBorderRadius = BorderRadius.zero; + customBoxShadow = [ + BoxShadow(color: shadowColor, blurRadius: 0.5, offset: const Offset(1, 0)), + BoxShadow(color: shadowColor, blurRadius: 0.5, offset: const Offset(-1, 0)), + ]; + } + + Widget widget = Material( + color: backgroundColor ?? themeData.colorScheme.surface, + child: child, + ); + + // Returns the customized widget + widget = Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + borderRadius: customBorderRadius, + boxShadow: customBoxShadow, ), + child: dividers && !bottom + ? Column( + children: [ + widget, + const Divider(), + ], + ) + : widget, ); + + if (!(top && bottom)) { + widget = ClipPath( + clipper: top + ? _topClipper + : bottom + ? _bottomClipper + : _middleClipper, + child: widget, + ); + } + + return widget; } @override @@ -72,22 +188,8 @@ class ZdsListTileWrapper extends StatelessWidget { super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('top', top)) - ..add(DiagnosticsProperty('bottom', bottom)); - } -} - -class _PaddingRect extends CustomClipper { - _PaddingRect(this.padding); - - final EdgeInsets padding; - - @override - Rect getClip(Size size) { - return Rect.fromLTRB(padding.left * -1, 0, size.width + (padding.horizontal), size.height); - } - - @override - bool shouldReclip(_PaddingRect oldClipper) { - return oldClipper.padding != padding; + ..add(DiagnosticsProperty('bottom', bottom)) + ..add(DiagnosticsProperty('addDivider', dividers)) + ..add(ColorProperty('backgroundColor', backgroundColor)); } } diff --git a/lib/src/components/molecules/menu.dart b/lib/src/components/molecules/menu.dart index 713f1dc..4b8457f 100644 --- a/lib/src/components/molecules/menu.dart +++ b/lib/src/components/molecules/menu.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Creates a popup menu. /// @@ -36,6 +36,15 @@ import '../../../zds_flutter.dart'; /// * [ZdsPopupMenuItem], used to create the options that appear in this menu. /// * [ZdsAppBar], where this component is used to show more actions that do not typically fit. class ZdsPopupMenu extends StatefulWidget { + /// Creates a pop up menu. + const ZdsPopupMenu({ + required this.builder, + required this.items, + super.key, + this.onCanceled, + this.onSelected, + }) : assert(items.length > 0, 'Must have at least 1 item'); + /// Defines how this component will appear on screen. /// /// Typically builds an [IconButton]. @@ -54,15 +63,6 @@ class ZdsPopupMenu extends StatefulWidget { /// A function called whenever the user doesn't select an item and instead closes the menu. final PopupMenuCanceled? onCanceled; - /// Creates a pop up menu. - const ZdsPopupMenu({ - required this.builder, - required this.items, - super.key, - this.onCanceled, - this.onSelected, - }) : assert(items.length > 0, 'Must have at least 1 item'); - @override ZdsPopupMenuState createState() => ZdsPopupMenuState(); @override @@ -132,7 +132,7 @@ class ZdsPopupMenuState extends State> { color: Colors.transparent, child: Builder( key: _key, - builder: (context) => IconTheme( + builder: (BuildContext context) => IconTheme( data: Theme.of(context).primaryIconTheme, child: widget.builder(context, _showButtonMenu(context)), ), diff --git a/lib/src/components/molecules/menu_item.dart b/lib/src/components/molecules/menu_item.dart index 2a393a8..7d3ef6d 100644 --- a/lib/src/components/molecules/menu_item.dart +++ b/lib/src/components/molecules/menu_item.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; const double _itemHeight = 56; @@ -33,6 +33,9 @@ const double _itemHeight = 56; /// /// * [ZdsNavigationMenu], used to create drawer navigation menus. class ZdsMenuItem extends StatelessWidget { + /// Creates a menu item for navigation. + const ZdsMenuItem({super.key, this.label, this.leading, this.title, this.trailing, this.onTap}); + /// A widget that will be shown before the title. /// /// Typically an [Icon]. @@ -56,11 +59,9 @@ class ZdsMenuItem extends StatelessWidget { /// A function called whenever a user taps on this component. final VoidCallback? onTap; - /// Creates a menu item for navigation. - const ZdsMenuItem({super.key, this.label, this.leading, this.title, this.trailing, this.onTap}); - @override Widget build(BuildContext context) { + final themeData = Theme.of(context); return Semantics( button: onTap != null, child: ConstrainedBox( @@ -68,22 +69,22 @@ class ZdsMenuItem extends StatelessWidget { child: InkWell( onTap: onTap, child: IconTheme.merge( - data: IconThemeData(size: 24, color: ZdsColors.greySwatch(context)[800]), + data: IconThemeData(size: 24, color: Zeta.of(context).colors.iconSubtle), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ if (label != null) ZdsNavigationMenuLabel(child: label!), Row( - children: [ + children: [ if (leading != null) IconTheme.merge( child: leading!, data: IconThemeData( - color: Theme.of(context).colorScheme.secondary, + color: themeData.colorScheme.secondary, ), ), if (title != null) Expanded(child: title!), @@ -91,7 +92,7 @@ class ZdsMenuItem extends StatelessWidget { ), ], ).textStyle( - Theme.of(context).textTheme.bodyMedium!.copyWith(color: Theme.of(context).colorScheme.onBackground), + themeData.textTheme.bodyLarge?.copyWith(color: themeData.colorScheme.onBackground), ), ), if (trailing != null) trailing!, diff --git a/lib/src/components/molecules/network_avatar.dart b/lib/src/components/molecules/network_avatar.dart index a4c64d0..ce39dad 100644 --- a/lib/src/components/molecules/network_avatar.dart +++ b/lib/src/components/molecules/network_avatar.dart @@ -1,7 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A circular container used to display a user's profile picture fetched from the internet. /// @@ -15,6 +15,21 @@ import '../../../zds_flutter.dart'; /// * [ZdsAvatar], an avatar used to display an image that is stored locally, or just the initials. /// * [CachedNetworkImage], which this avatar uses to not have to download the image every time. class ZdsNetworkAvatar extends StatelessWidget implements PreferredSizeWidget { + /// An avatar that gets its image from an URL. + const ZdsNetworkAvatar({ + required this.initials, + this.url = '', + this.onTap, + this.size, + this.textStyle, + this.backgroundColor, + this.semanticLabelAvatarDescription, + this.imgCacheKey, + this.headers, + this.fit, + super.key, + }) : assert(size != null ? size >= 0 : size == null, 'Size must be greater than 0'); + /// The URL from which to fetch the image. final String url; @@ -53,31 +68,17 @@ class ZdsNetworkAvatar extends StatelessWidget implements PreferredSizeWidget { /// How to inscribe the image into the space allocated during layout. final BoxFit? fit; - /// An avatar that gets its image from an URL. - const ZdsNetworkAvatar({ - required this.initials, - this.url = '', - this.onTap, - this.size, - this.textStyle, - this.backgroundColor, - this.semanticLabelAvatarDescription, - this.imgCacheKey, - this.headers, - this.fit, - super.key, - }) : assert(size != null ? size >= 0 : size == null, 'Size must be greater than 0'); - @override Widget build(BuildContext context) { - final initialsWidget = Center( + final themeData = Theme.of(context); + final Center initialsWidget = Center( child: Text( initials, textScaleFactor: 1, style: textStyle ?? - Theme.of(context).textTheme.bodyLarge?.copyWith( - color: calculateTextColor(backgroundColor ?? Theme.of(context).colorScheme.secondary), - ), + themeData.textTheme.displaySmall?.copyWith( + color: (backgroundColor ?? themeData.colorScheme.secondary).onColor, + ), ), ); @@ -87,7 +88,7 @@ class ZdsNetworkAvatar extends StatelessWidget implements PreferredSizeWidget { height: size ?? preferredSize.height, width: size ?? preferredSize.width, decoration: BoxDecoration( - color: backgroundColor ?? Theme.of(context).colorScheme.secondary, + color: backgroundColor ?? themeData.colorScheme.secondary, shape: BoxShape.circle, ), child: Semantics( @@ -96,7 +97,7 @@ class ZdsNetworkAvatar extends StatelessWidget implements PreferredSizeWidget { child: Uri.tryParse(url)?.hasAbsolutePath ?? false ? CachedNetworkImage( cacheKey: imgCacheKey, - imageBuilder: (context, imageProvider) { + imageBuilder: (BuildContext context, ImageProvider imageProvider) { return Container( decoration: BoxDecoration( shape: BoxShape.circle, @@ -106,8 +107,8 @@ class ZdsNetworkAvatar extends StatelessWidget implements PreferredSizeWidget { }, imageUrl: url, httpHeaders: headers, - placeholder: (context, _) => initialsWidget, - errorWidget: (context, _, error) => initialsWidget, + placeholder: (BuildContext context, _) => initialsWidget, + errorWidget: (BuildContext context, _, Object error) => initialsWidget, ) : initialsWidget, ), @@ -119,23 +120,19 @@ class ZdsNetworkAvatar extends StatelessWidget implements PreferredSizeWidget { @override Size get preferredSize => const Size(48, 48); - /// Sets the default text color based on the background color. - Color calculateTextColor(Color background) { - return ThemeData.estimateBrightnessForColor(background) == Brightness.light ? ZdsColors.darkGrey : ZdsColors.white; - } - @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('url', url)); - properties.add(StringProperty('initials', initials)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(DoubleProperty('size', size)); - properties.add(DiagnosticsProperty('textStyle', textStyle)); - properties.add(ColorProperty('backgroundColor', backgroundColor)); - properties.add(StringProperty('semanticLabelAvatarDescription', semanticLabelAvatarDescription)); - properties.add(StringProperty('imgCacheKey', imgCacheKey)); - properties.add(DiagnosticsProperty?>('headers', headers)); - properties.add(EnumProperty('fit', fit)); + properties + ..add(StringProperty('url', url)) + ..add(StringProperty('initials', initials)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(DoubleProperty('size', size)) + ..add(DiagnosticsProperty('textStyle', textStyle)) + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(StringProperty('semanticLabelAvatarDescription', semanticLabelAvatarDescription)) + ..add(StringProperty('imgCacheKey', imgCacheKey)) + ..add(DiagnosticsProperty?>('headers', headers)) + ..add(EnumProperty('fit', fit)); } } diff --git a/lib/src/components/molecules/resizeable_text_area.dart b/lib/src/components/molecules/resizeable_text_area.dart index 217cd3f..d95afa5 100644 --- a/lib/src/components/molecules/resizeable_text_area.dart +++ b/lib/src/components/molecules/resizeable_text_area.dart @@ -1,10 +1,30 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A text input area with handle icon in the bottom right corner that can be used to resize the typing input area. class ZdsResizableTextArea extends StatefulWidget { + /// Constructs a [ZdsResizableTextArea]. + const ZdsResizableTextArea({ + super.key, + this.textInputAction = TextInputAction.none, + this.hintText, + this.label, + this.maxLines, + this.height = 100, + this.maxHeight = double.infinity, + this.minHeight = 48, + this.textStyle, + this.controller, + this.onChanged, + this.focusNode, + this.enabled = true, + this.footerText, + this.decoration, + this.semanticLabel, + }); + /// The [textInputAction]'s input action button of keyboard of the text field/box /// /// Defaults to [TextInputAction.none]. @@ -60,46 +80,28 @@ class ZdsResizableTextArea extends StatefulWidget { /// Input decoration used for underlying TextField. final InputDecoration? decoration; - /// Constructs a [ZdsResizableTextArea]. - const ZdsResizableTextArea({ - super.key, - this.textInputAction = TextInputAction.none, - this.hintText, - this.label, - this.maxLines, - this.height = 100, - this.maxHeight = double.infinity, - this.minHeight = 48, - this.textStyle, - this.controller, - this.onChanged, - this.focusNode, - this.enabled = true, - this.footerText, - this.decoration, - this.semanticLabel, - }); - @override State createState() => _ZdsResizableTextAreaState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(EnumProperty('textInputAction', textInputAction)); - properties.add(DoubleProperty('height', height)); - properties.add(DoubleProperty('maxHeight', maxHeight)); - properties.add(DoubleProperty('minHeight', minHeight)); - properties.add(StringProperty('hintText', hintText)); - properties.add(StringProperty('label', label)); - properties.add(StringProperty('semanticLabel', semanticLabel)); - properties.add(IntProperty('maxLines', maxLines)); - properties.add(DiagnosticsProperty('textStyle', textStyle)); - properties.add(DiagnosticsProperty('controller', controller)); - properties.add(ObjectFlagProperty?>.has('onChanged', onChanged)); - properties.add(DiagnosticsProperty('focusNode', focusNode)); - properties.add(DiagnosticsProperty('enabled', enabled)); - properties.add(StringProperty('footerText', footerText)); - properties.add(DiagnosticsProperty('decoration', decoration)); + properties + ..add(EnumProperty('textInputAction', textInputAction)) + ..add(DoubleProperty('height', height)) + ..add(DoubleProperty('maxHeight', maxHeight)) + ..add(DoubleProperty('minHeight', minHeight)) + ..add(StringProperty('hintText', hintText)) + ..add(StringProperty('label', label)) + ..add(StringProperty('semanticLabel', semanticLabel)) + ..add(IntProperty('maxLines', maxLines)) + ..add(DiagnosticsProperty('textStyle', textStyle)) + ..add(DiagnosticsProperty('controller', controller)) + ..add(ObjectFlagProperty?>.has('onChanged', onChanged)) + ..add(DiagnosticsProperty('focusNode', focusNode)) + ..add(DiagnosticsProperty('enabled', enabled)) + ..add(StringProperty('footerText', footerText)) + ..add(DiagnosticsProperty('decoration', decoration)); } } @@ -126,19 +128,22 @@ class _ZdsResizableTextAreaState extends State { @override Widget build(BuildContext context) { - return Semantics( - textField: true, - readOnly: !widget.enabled, - onTap: () => widget.focusNode?.requestFocus(), - excludeSemantics: true, - label: '${widget.label ?? widget.semanticLabel} ${textEditingController.text}', - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack( - children: [ - SizedBox( - height: _height, + final zetaColors = Zeta.of(context).colors; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + children: [ + SizedBox( + height: _height, + child: Semantics( + excludeSemantics: true, + enabled: widget.enabled, + onSetText: (value) => { + textEditingController.text = value, + widget.onChanged?.call(value), + }, + label: '${widget.label ?? widget.semanticLabel} ${textEditingController.text}', child: TextField( textInputAction: widget.textInputAction, style: widget.textStyle ?? Theme.of(context).textTheme.bodyMedium, @@ -146,7 +151,7 @@ class _ZdsResizableTextAreaState extends State { ZdsInputDecoration( labelText: widget.label, hintText: widget.hintText, - fillColor: !widget.enabled ? ZdsColors.greySwatch(context).shade300 : null, + fillColor: !widget.enabled ? zetaColors.surfaceDisabled : null, filled: !widget.enabled, ), maxLines: widget.maxLines, @@ -157,56 +162,57 @@ class _ZdsResizableTextAreaState extends State { key: key, ), ), - Positioned( - bottom: 12, - right: 4, - child: GestureDetector( - child: Container( - alignment: Alignment.bottomRight, - height: 48, - width: 48, - child: Icon( - ZdsIcons.expand, - size: 18, - color: ZdsColors.greySwatch(context).shade800, - ).padding(4), - ), - onVerticalDragUpdate: (details) { - setState(() { - _height += details.delta.dy; - // prevent overflow if height is more/less than available space - // Min height is 1 line - final minLimit = (widget.minHeight / 2) * MediaQuery.of(context).devicePixelRatio + 24; - if (_height > widget.maxHeight) { - _height = widget.maxHeight; - } else if (_height < minLimit) { - _height = minLimit; - } - }); - }, + ), + Positioned( + bottom: 12, + right: 4, + child: GestureDetector( + child: Container( + alignment: Alignment.bottomRight, + height: 48, + width: 48, + child: Icon( + ZdsIcons.expand, + size: 18, + color: zetaColors.iconSubtle, + ).padding(4), ), - ), - ], - ), - if (widget.footerText != null) - Transform.translate( - offset: const Offset(0, -8), - child: Text( - widget.footerText!, - style: Theme.of(context).textTheme.bodySmall?.copyWith(color: ZdsColors.greySwatch(context)[1000]), - overflow: TextOverflow.ellipsis, - maxLines: 2, + onVerticalDragUpdate: (DragUpdateDetails details) { + setState(() { + _height += details.delta.dy; + // prevent overflow if height is more/less than available space + // Min height is 1 line + final double minLimit = (widget.minHeight / 2) * MediaQuery.of(context).devicePixelRatio + 24; + if (_height > widget.maxHeight) { + _height = widget.maxHeight; + } else if (_height < minLimit) { + _height = minLimit; + } + }); + }, ), ), - ], - ), + ], + ), + if (widget.footerText != null) + Transform.translate( + offset: const Offset(0, -8), + child: Text( + widget.footerText!, + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: zetaColors.textDisabled), + overflow: TextOverflow.ellipsis, + maxLines: 2, + ), + ), + ], ); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty>>('key', key)); - properties.add(DiagnosticsProperty('textEditingController', textEditingController)); + properties + ..add(DiagnosticsProperty>>('key', key)) + ..add(DiagnosticsProperty('textEditingController', textEditingController)); } } diff --git a/lib/src/components/molecules/responsive_tab_bar.dart b/lib/src/components/molecules/responsive_tab_bar.dart index 99161b2..a0e3022 100644 --- a/lib/src/components/molecules/responsive_tab_bar.dart +++ b/lib/src/components/molecules/responsive_tab_bar.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A TabBar that solves certain issues with Material's TabBar. When using isScrollable is set to true in TabBar, the /// tabs will not fit the device's width. When isScrollable is set to false, the tabs all have the same size and do not @@ -43,6 +43,7 @@ class ZdsResponsiveTabBar extends StatelessWidget { this.color = ZdsTabBarColor.surface, this.selectedLabelFontWeight, this.topSafeArea = true, + this.bottomSafeArea = false, this.indicatorColor, this.selectedTextColor, this.textColor, @@ -82,42 +83,52 @@ class ZdsResponsiveTabBar extends StatelessWidget { /// This will be deprecated in future release, as the value should be autogenerated based on the [color]. final Color? indicatorColor; - /// Determine's whether component observes safe area of screen. + /// Determine's whether component observes safe area at top of the screen. + /// + /// Defaults to true. /// /// See also: /// * [SafeArea]. final bool topSafeArea; + /// Determine's whether component observes safe area at bottom of the screen. + /// + /// Defaults to false. + /// + /// See also: + /// * [SafeArea]. + final bool bottomSafeArea; + @override Widget build(BuildContext context) { final int numberOfTabs = tabs.length; - final appBar = context.findAncestorWidgetOfExactType(); + final ZdsAppBar? appBar = context.findAncestorWidgetOfExactType(); - final customThemeContainer = Theme.of(context).zdsTabBarThemeData( + final customThemeContainer = ZdsTabBar.buildTheme( context, + color: appBar != null ? appBar.color : color, hasIcons: hasIcons(tabs), - )[appBar != null ? appBar.color : color]!; - final customTheme = customThemeContainer.customTheme; + ); - return Container( - color: (customThemeContainer.customTheme.decoration as BoxDecoration).color, + final ZdsTabBarThemeData customTheme = customThemeContainer.customTheme; + + return DecoratedBox( + decoration: customTheme.decoration, child: SafeArea( - bottom: false, top: topSafeArea, + bottom: bottomSafeArea, child: LayoutBuilder( builder: (context, constraints) { // 16*2 refers to kTabLabelPadding (on both sides of the label) - var minWidth = constraints.maxWidth / numberOfTabs - (16 * 2); + double minWidth = constraints.maxWidth / numberOfTabs - (16 * 2); minWidth = minWidth > 0 ? minWidth : 12; - - return Container( - height: customTheme.height + 1, - decoration: customTheme.decoration, - child: Theme( - data: customThemeContainer.theme, + return Theme( + data: customThemeContainer.theme, + child: SizedBox( + height: customTheme.height + 1, child: TabBar( controller: controller, - indicatorWeight: 5, + indicatorWeight: 1, isScrollable: true, labelStyle: (hasIcons(tabs) ? Theme.of(context).textTheme.bodySmall : Theme.of(context).textTheme.bodyLarge) @@ -127,8 +138,8 @@ class ZdsResponsiveTabBar extends StatelessWidget { labelColor: selectedTextColor, unselectedLabelColor: textColor, indicatorColor: indicatorColor, - tabs: [ - for (final tab in tabs) + tabs: [ + for (final ZdsTab tab in tabs) ConstrainedBox( constraints: BoxConstraints(minWidth: minWidth), child: tab, @@ -153,6 +164,7 @@ class ZdsResponsiveTabBar extends StatelessWidget { ..add(DiagnosticsProperty('topSafeArea', topSafeArea)) ..add(ColorProperty('selectedTextColor', selectedTextColor)) ..add(ColorProperty('textColor', textColor)) - ..add(ColorProperty('indicatorColor', indicatorColor)); + ..add(ColorProperty('indicatorColor', indicatorColor)) + ..add(DiagnosticsProperty('bottomSafeArea', bottomSafeArea)); } } diff --git a/lib/src/components/molecules/search.dart b/lib/src/components/molecules/search.dart index c59b93b..c34f82d 100644 --- a/lib/src/components/molecules/search.dart +++ b/lib/src/components/molecules/search.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Variants of [ZdsSearchField]. enum ZdsSearchFieldVariant { @@ -26,6 +26,22 @@ enum ZdsSearchFieldVariant { /// * [ZdsSearchAppBar], an appBar that uses this component. /// * [ZdsEmpty], which can be used to show a no results message. class ZdsSearchField extends StatelessWidget { + /// A search field that can be used in a form. + const ZdsSearchField({ + super.key, + this.textFormFieldKey, + this.variant = ZdsSearchFieldVariant.elevated, + this.onChange, + this.initValue, + this.hintText, + this.onSubmit, + this.focusNode, + this.padding = const EdgeInsets.all(12), + this.suffixIcon, + this.controller, + this.inputAction = TextInputAction.search, + }); + /// The Key to use for the underlying [TextFormField]. final Key? textFormFieldKey; @@ -69,26 +85,11 @@ class ZdsSearchField extends StatelessWidget { /// A controller that can be used to notify listeners when the text changes. final TextEditingController? controller; - /// A search field that can be used in a form. - const ZdsSearchField({ - super.key, - this.textFormFieldKey, - this.variant = ZdsSearchFieldVariant.elevated, - this.onChange, - this.initValue, - this.hintText, - this.onSubmit, - this.focusNode, - this.padding = const EdgeInsets.all(12), - this.suffixIcon, - this.controller, - this.inputAction = TextInputAction.search, - }); - @override Widget build(BuildContext context) { - final defaultTheme = Theme.of(context); - final effectiveTheme = defaultTheme.zdsSearchThemeData[variant] ?? defaultTheme; + final ThemeData defaultTheme = Theme.of(context); + final zetaColors = Zeta.of(context).colors; + final ThemeData effectiveTheme = defaultTheme.zdsSearchThemeData(defaultTheme, variant, zetaColors); return Theme( data: effectiveTheme, child: Padding( @@ -96,22 +97,29 @@ class ZdsSearchField extends StatelessWidget { child: ZdsCard( padding: EdgeInsets.zero, backgroundColor: effectiveTheme.colorScheme.surface, - child: TextFormField( - style: effectiveTheme.textTheme.bodyLarge?.copyWith(color: effectiveTheme.colorScheme.onSurface), - autocorrect: false, - textInputAction: inputAction, - key: textFormFieldKey, - focusNode: focusNode, - controller: controller, - initialValue: controller == null ? initValue : null, - onChanged: onChange, - onFieldSubmitted: onSubmit, - decoration: InputDecoration( - constraints: const BoxConstraints(minHeight: 48, minWidth: 48), - hintText: hintText, - prefixIcon: effectiveTheme.prefixIcon, - contentPadding: EdgeInsets.zero, - suffixIcon: suffixIcon, + child: Semantics( + excludeSemantics: true, + onSetText: (value) => { + controller?.text = value, + onChange?.call(value), + }, + label: (controller != null && controller!.text.isNotEmpty) ? controller!.text : hintText, + child: TextFormField( + style: effectiveTheme.textTheme.bodyLarge?.copyWith(color: effectiveTheme.colorScheme.onSurface), + autocorrect: false, + textInputAction: inputAction, + focusNode: focusNode, + controller: controller, + initialValue: controller == null ? initValue : null, + onChanged: onChange, + onFieldSubmitted: onSubmit, + decoration: InputDecoration( + constraints: const BoxConstraints(minHeight: 48, minWidth: 48), + hintText: hintText, + prefixIcon: effectiveTheme.prefixIcon, + contentPadding: EdgeInsets.zero, + suffixIcon: suffixIcon, + ), ), ), ), @@ -122,15 +130,16 @@ class ZdsSearchField extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('textFormFieldKey', textFormFieldKey)); - properties.add(EnumProperty('variant', variant)); - properties.add(StringProperty('initValue', initValue)); - properties.add(StringProperty('hintText', hintText)); - properties.add(ObjectFlagProperty.has('onChange', onChange)); - properties.add(ObjectFlagProperty.has('onSubmit', onSubmit)); - properties.add(DiagnosticsProperty('focusNode', focusNode)); - properties.add(DiagnosticsProperty('padding', padding)); - properties.add(EnumProperty('inputAction', inputAction)); - properties.add(DiagnosticsProperty('controller', controller)); + properties + ..add(DiagnosticsProperty('textFormFieldKey', textFormFieldKey)) + ..add(EnumProperty('variant', variant)) + ..add(StringProperty('initValue', initValue)) + ..add(StringProperty('hintText', hintText)) + ..add(ObjectFlagProperty.has('onChange', onChange)) + ..add(ObjectFlagProperty.has('onSubmit', onSubmit)) + ..add(DiagnosticsProperty('focusNode', focusNode)) + ..add(DiagnosticsProperty('padding', padding)) + ..add(EnumProperty('inputAction', inputAction)) + ..add(DiagnosticsProperty('controller', controller)); } } diff --git a/lib/src/components/molecules/selectable_list_tile.dart b/lib/src/components/molecules/selectable_list_tile.dart index baa9f8e..6b0ec0c 100644 --- a/lib/src/components/molecules/selectable_list_tile.dart +++ b/lib/src/components/molecules/selectable_list_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A list tile with circular edges that can be toggled between a selected and unselected state. /// @@ -14,6 +14,30 @@ import '../../../zds_flutter.dart'; /// This widget does not manage its own state, but should rather be rebuilt by the parent widget's state through /// [onTap]. class ZdsSelectableListTile extends StatelessWidget { + /// A tile with rounded edges that can be toggled as selected or unselected. + const ZdsSelectableListTile({ + super.key, + this.leading, + this.title, + this.subTitle, + this.trailing, + this.onTap, + this.selected = false, + this.semanticLabel, + }) : _checkable = false; + + /// A tile with rounded edges that can be toggled as selected or unselected and shows a check icon when selected. + const ZdsSelectableListTile.checkable({ + super.key, + this.leading, + this.title, + this.subTitle, + this.selected = false, + this.onTap, + this.semanticLabel, + }) : trailing = const Icon(ZdsIcons.check), + _checkable = true; + /// A widget shown before the title. /// /// Usually an indicator of whether the tile is selected or not. @@ -49,52 +73,29 @@ class ZdsSelectableListTile extends StatelessWidget { /// this is for talk back text final String? semanticLabel; - /// A tile with rounded edges that can be toggled as selected or unselected. - const ZdsSelectableListTile({ - super.key, - this.leading, - this.title, - this.subTitle, - this.trailing, - this.onTap, - this.selected = false, - this.semanticLabel, - }) : _checkable = false; - - /// A tile with rounded edges that can be toggled as selected or unselected and shows a check icon when selected. - const ZdsSelectableListTile.checkable({ - super.key, - this.leading, - this.title, - this.subTitle, - this.selected = false, - this.onTap, - this.semanticLabel, - }) : trailing = const Icon(ZdsIcons.check), - _checkable = true; - @override Widget build(BuildContext context) { - const padding = EdgeInsets.symmetric(horizontal: 24, vertical: 12); - const innerPadding = EdgeInsets.symmetric(horizontal: 14, vertical: 12); + const EdgeInsets padding = EdgeInsets.symmetric(horizontal: 24, vertical: 12); + const EdgeInsets innerPadding = EdgeInsets.symmetric(horizontal: 14, vertical: 12); + + final bool showSelected = (_checkable && selected) || (!_checkable && selected); - final showSelected = (_checkable && selected) || (!_checkable && selected); + final themeData = Theme.of(context); + final zetaColors = Zeta.of(context).colors; return IconTheme( - data: Theme.of(context).iconTheme.copyWith(size: 24, color: Theme.of(context).colorScheme.secondary), + data: themeData.iconTheme.copyWith(size: 24, color: zetaColors.secondary.icon), child: Padding( padding: kZdsSelectableListTilePadding, child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(kZdsSelectableListTileBorderRadius)), child: Material( - color: showSelected - ? Theme.of(context).colorScheme.secondary.withOpacity(0.1) - : Theme.of(context).colorScheme.surface, + color: showSelected ? zetaColors.secondary.surface : themeData.colorScheme.surface, child: DecoratedBox( decoration: BoxDecoration( border: showSelected - ? Border.all(color: Theme.of(context).colorScheme.secondary) - : Border.all(color: ZdsColors.lightGrey), + ? Border.all(color: zetaColors.secondary.border) + : Border.all(color: zetaColors.borderSubtle), borderRadius: const BorderRadius.all(Radius.circular(kZdsSelectableListTileBorderRadius)), ), child: InkWell( @@ -116,7 +117,7 @@ class ZdsSelectableListTile extends StatelessWidget { bottom: 0, ), child: Row( - children: [ + children: [ if (leading != null) leading!, if (title != null) Expanded( @@ -129,17 +130,16 @@ class ZdsSelectableListTile extends StatelessWidget { ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ title!, - Container(child: subTitle).textStyle( - Theme.of(context) - .textTheme - .titleSmall! - .copyWith(color: ZdsColors.blueGrey, fontSize: 12), - ), + if (subTitle != null) + Container(child: subTitle).textStyle( + themeData.textTheme.titleSmall! + .copyWith(color: zetaColors.textSubtle, fontSize: 12), + ), ], ), - ).textStyle(Theme.of(context).textTheme.titleSmall), + ).textStyle(themeData.textTheme.titleSmall), ), if ((trailing != null && !_checkable) || (_checkable && selected)) trailing!, ], @@ -158,8 +158,9 @@ class ZdsSelectableListTile extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('selected', selected)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(StringProperty('semanticLabel', semanticLabel)); + properties + ..add(DiagnosticsProperty('selected', selected)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(StringProperty('semanticLabel', semanticLabel)); } } diff --git a/lib/src/components/molecules/sheet_header.dart b/lib/src/components/molecules/sheet_header.dart index 73b5da0..da04808 100644 --- a/lib/src/components/molecules/sheet_header.dart +++ b/lib/src/components/molecules/sheet_header.dart @@ -2,11 +2,20 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/semantics.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Creates the header component for a bottom sheet with Zds style. class ZdsSheetHeader extends StatelessWidget implements PreferredSizeWidget { - static const _kSheetHeight = 54.0; + /// Constructs a [ZdsSheetHeader]. + const ZdsSheetHeader({ + required this.headerText, + super.key, + this.leading, + this.trailing, + this.busy = false, + this.headerTextStyle, + }); + static const double _kSheetHeight = 54; /// Sheet header title of type [String]. final String headerText; @@ -27,21 +36,12 @@ class ZdsSheetHeader extends StatelessWidget implements PreferredSizeWidget { /// Defaults to [TextTheme.headlineMedium]. final TextStyle? headerTextStyle; - /// Constructs a [ZdsSheetHeader]. - const ZdsSheetHeader({ - required this.headerText, - super.key, - this.leading, - this.trailing, - this.busy = false, - this.headerTextStyle, - }); - @override Widget build(BuildContext context) { + final themeData = Theme.of(context); return Semantics( child: Container( - color: Theme.of(context).colorScheme.surface, + color: themeData.colorScheme.surface, height: _kSheetHeight, width: double.infinity, child: Material( @@ -50,18 +50,19 @@ class ZdsSheetHeader extends StatelessWidget implements PreferredSizeWidget { top: false, bottom: false, child: Stack( - children: [ + children: [ Center( child: Text( headerText, - style: headerTextStyle ?? Theme.of(context).textTheme.titleLarge, + style: headerTextStyle ?? themeData.textTheme.headlineMedium, overflow: TextOverflow.ellipsis, textScaleFactor: MediaQuery.of(context).textScaleFactor > 2 ? 2 : null, ), ).paddingOnly(bottom: 5), if (leading != null) - leading.runtimeType == IconButton - ? Padding( + leading is IconButton || leading is Icon + ? Container( + height: _kSheetHeight, padding: EdgeInsets.only(left: context.isTablet() ? 0 : 16), child: Material( shape: const CircleBorder(), @@ -70,10 +71,10 @@ class ZdsSheetHeader extends StatelessWidget implements PreferredSizeWidget { child: Semantics( sortKey: const OrdinalSortKey(1), child: IconTheme( - data: Theme.of(context).iconTheme.copyWith( - color: ZdsColors.greySwatch(context)[1000], - size: 24, - ), + data: themeData.iconTheme.copyWith( + color: Zeta.of(context).colors.iconSubtle, + size: 24, + ), child: leading!, ), ), @@ -104,8 +105,9 @@ class ZdsSheetHeader extends StatelessWidget implements PreferredSizeWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('headerText', headerText)); - properties.add(DiagnosticsProperty('busy', busy)); - properties.add(DiagnosticsProperty('headerTextStyle', headerTextStyle)); + properties + ..add(StringProperty('headerText', headerText)) + ..add(DiagnosticsProperty('busy', busy)) + ..add(DiagnosticsProperty('headerTextStyle', headerTextStyle)); } } diff --git a/lib/src/components/molecules/slidable_button.dart b/lib/src/components/molecules/slidable_button.dart index 74c309d..a5a3ea0 100644 --- a/lib/src/components/molecules/slidable_button.dart +++ b/lib/src/components/molecules/slidable_button.dart @@ -1,14 +1,32 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; - -// TODO(colors): Fix colors on track. +import '../../../../zds_flutter.dart'; /// A SlidableButton with pre-applied Zds styling. /// This grows to the width of its container. class ZdsSlidableButton extends StatefulWidget { + /// A button slider with a [ZdsSlidableWidget] as a child, the [ZdsSlidableWidget] is the slidable element. + const ZdsSlidableButton({ + required this.buttonSliderColor, + required this.buttonText, + required this.buttonIcon, + required this.buttonColor, + this.onTapDown, + this.onSlideComplete, + this.animate = true, + this.buttonSliderColorEnd, + this.buttonColorEnd, + this.buttonTextEnd, + this.buttonIconEnd, + this.stayCompleted = false, + this.disabledMessage, + this.completedDisplayDuration = const Duration(seconds: 2), + this.handleWidth = 160, + this.height = 64, + super.key, + }); + /// The future that is called when the button has been slid. /// While it is being awaited, a loading indicator will show. /// If the future returns true, the text and colors will be switched out for their 'end' equivalents @@ -18,107 +36,73 @@ class ZdsSlidableButton extends StatefulWidget { /// Called when the handle is tapped. final void Function()? onTapDown; - /// Button background color. - final Color? buttonSliderColor; + /// Button background color + final Color buttonSliderColor; - /// Button color default. - /// - /// Defaults to `colors.primary`. - final Color? buttonColor; + /// Button color + final Color buttonColor; - /// Button center text. - final String? buttonText; + /// Button center text + final String buttonText; - /// Button Icon when toggled. - final IconData? buttonIcon; + /// Button Icon when toggled + final IconData buttonIcon; - /// Button background color when toggled. + /// Button background color when toggled final Color? buttonSliderColorEnd; - /// Button color when toggled default. - /// - /// Defaults to `buttonColor.withOpacity(0.5)`, or if [buttonColor] is null, `colors.subtle`. + /// Button color when toggled final Color? buttonColorEnd; - /// Button center text when toggled. + /// Button center text when toggled final String? buttonTextEnd; - /// Button Icon when toggled. + /// Button Icon when toggled final IconData? buttonIconEnd; - /// Button animation after slide, this is defaulted to false for no animation. + /// Button animation after slide, this is defaulted to false for no animation final bool animate; - /// Circle indicator color. - final Animation? indicatorColor; - - /// Keeps the toggle at one end after completion. + /// Keeps the toggle at one end after completion final bool stayCompleted; /// The duration to show the completed widget before the toggle resets. - /// Will not do anything if [stayCompleted] is set to true. + /// Will not do anything if [stayCompleted] is set to true final Duration completedDisplayDuration; /// The message to be displayed when the button is disabled. /// Only shows if [onSlideComplete] is null. final String? disabledMessage; - /// The height of the button. + /// The height of the button final double height; - /// The width of the button handle. + /// The width of the button handle final double handleWidth; - /// Base color used for button. - final ZetaColorSwatch? colors; - - /// A button slider with a [ZdsSlidableWidget] as a child, the [ZdsSlidableWidget] is the slidable element. - const ZdsSlidableButton({ - this.buttonText, - this.buttonIcon, - this.buttonSliderColor, - this.buttonColor, - this.onTapDown, - this.onSlideComplete, - this.animate = true, - this.indicatorColor = const AlwaysStoppedAnimation(Colors.white), - this.buttonSliderColorEnd, - this.buttonColorEnd, - this.buttonTextEnd, - this.buttonIconEnd, - this.stayCompleted = false, - this.disabledMessage, - this.completedDisplayDuration = const Duration(seconds: 2), - this.handleWidth = 160, - this.height = 64, - this.colors, - super.key, - }); - @override ZdsSlidableButtonState createState() => ZdsSlidableButtonState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(ObjectFlagProperty Function()?>.has('onSlideComplete', onSlideComplete)); - properties.add(DiagnosticsProperty('onTapDown', onTapDown)); - properties.add(ColorProperty('buttonSliderColor', buttonSliderColor)); - properties.add(ColorProperty('buttonColor', buttonColor)); - properties.add(StringProperty('buttonText', buttonText)); - properties.add(DiagnosticsProperty('buttonIcon', buttonIcon)); - properties.add(ColorProperty('buttonSliderColorEnd', buttonSliderColorEnd)); - properties.add(ColorProperty('buttonColorEnd', buttonColorEnd)); - properties.add(StringProperty('buttonTextEnd', buttonTextEnd)); - properties.add(DiagnosticsProperty('buttonIconEnd', buttonIconEnd)); - properties.add(DiagnosticsProperty('animate', animate)); - properties.add(DiagnosticsProperty?>('indicatorColor', indicatorColor)); - properties.add(DiagnosticsProperty('stayCompleted', stayCompleted)); - properties.add(DiagnosticsProperty('completedDisplayDuration', completedDisplayDuration)); - properties.add(StringProperty('disabledMessage', disabledMessage)); - properties.add(DoubleProperty('height', height)); - properties.add(DoubleProperty('handleWidth', handleWidth)); - properties.add(ColorProperty('colors', colors)); + properties + ..add(ObjectFlagProperty Function()?>.has('onSlideComplete', onSlideComplete)) + ..add(DiagnosticsProperty('onTapDown', onTapDown)) + ..add(ColorProperty('buttonSliderColor', buttonSliderColor)) + ..add(ColorProperty('buttonColor', buttonColor)) + ..add(StringProperty('buttonText', buttonText)) + ..add(DiagnosticsProperty('buttonIcon', buttonIcon)) + ..add(ColorProperty('buttonSliderColorEnd', buttonSliderColorEnd)) + ..add(ColorProperty('buttonColorEnd', buttonColorEnd)) + ..add(StringProperty('buttonTextEnd', buttonTextEnd)) + ..add(DiagnosticsProperty('buttonIconEnd', buttonIconEnd)) + ..add(DiagnosticsProperty('animate', animate)) + ..add(DiagnosticsProperty('stayCompleted', stayCompleted)) + ..add(DiagnosticsProperty('completedDisplayDuration', completedDisplayDuration)) + ..add(StringProperty('disabledMessage', disabledMessage)) + ..add(DoubleProperty('height', height)) + ..add(DoubleProperty('handleWidth', handleWidth)); } } @@ -128,7 +112,7 @@ class ZdsSlidableButtonState extends State { bool _isLoading = false; bool _isTapedDown = false; - final GlobalKey _slideableKey = GlobalKey(); + final GlobalKey _slideableKey = GlobalKey(); @override void initState() { @@ -141,28 +125,29 @@ class ZdsSlidableButtonState extends State { _isLoading = true; }); final isSuccessful = await widget.onSlideComplete!.call(); - if (mounted) { - setState(() { - _isLoading = false; - _isTapedDown = false; - }); - } + if (!mounted) return; + setState(() { + _isLoading = false; + _isTapedDown = false; + }); if (isSuccessful) { setState(() { _isComplete = true; }); if (!widget.stayCompleted) { await Future.delayed(widget.completedDisplayDuration); + reset(); } + } else { + reset(); } } - if (!widget.stayCompleted) reset(); } /// Resets the slider. void reset() { - if (_slideableKey.currentWidget is ZdsSlidableWidgetState) { - (_slideableKey.currentState! as ZdsSlidableWidgetState).reset(); + _slideableKey.currentState?.reset(); + if (mounted) { setState(() { _isTapedDown = false; _isComplete = false; @@ -172,136 +157,133 @@ class ZdsSlidableButtonState extends State { @override Widget build(BuildContext context) { - final ZetaColorSwatch colors = widget.colors ?? ZetaColors.of(context).primary; - - final Color buttonSliderColorEnd = widget.buttonSliderColorEnd ?? colors.shade20; - final Color buttonSliderColor = widget.buttonSliderColorEnd ?? colors.shade20; - final Color buttonColor = widget.buttonColor ?? colors.primary; - final Color buttonColorComplete = widget.buttonColor?.withOpacity(0.5) ?? colors.subtle; - final showDisabledMessage = widget.disabledMessage != null && widget.onSlideComplete == null; - return Wrap( - children: [ - AnimatedContainer( - duration: const Duration(milliseconds: 200), - height: widget.height, - decoration: BoxDecoration( - color: showDisabledMessage - ? null - : widget.buttonSliderColorEnd != null && _isComplete - ? buttonSliderColorEnd - : buttonSliderColor, - borderRadius: BorderRadius.circular(widget.height), - ), - child: Stack( - children: [ - ZdsSlidableWidget( - key: _slideableKey, - animate: widget.animate, - isActive: widget.onSlideComplete != null && !_isLoading && !_isComplete, - height: widget.height, - onTapDown: () { - widget.onTapDown?.call(); - setState(() { - _isTapedDown = true; - }); - }, - onTapUp: () { - setState(() { - _isTapedDown = false; - }); - }, - slidePercentageNeeded: 0.55, - handleWidth: widget.handleWidth, - stayCompleted: widget.stayCompleted, - onSlide: _onSlideComplete, - child: SizedBox( + final buttonColor = widget.buttonColorEnd != null && widget.animate && (_isLoading || _isTapedDown || _isComplete) + ? widget.buttonColorEnd! + : widget.onSlideComplete != null + ? widget.buttonColor + : widget.buttonColor.withOpacity(0.5); + + return Semantics( + slider: true, + label: widget.buttonText, + excludeSemantics: true, + button: true, + onTap: () { + _slideableKey.currentState?.complete(); + }, + child: Wrap( + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 200), + height: widget.height, + decoration: BoxDecoration( + color: showDisabledMessage + ? null + : widget.buttonSliderColorEnd != null && _isComplete + ? widget.buttonSliderColorEnd + : widget.buttonSliderColor, + borderRadius: BorderRadius.circular(widget.height), + ), + child: Stack( + children: [ + ZdsSlidableWidget( + key: _slideableKey, + animate: widget.animate, + isActive: widget.onSlideComplete != null && !_isLoading && !_isComplete, height: widget.height, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Material( - elevation: 2, - borderRadius: BorderRadius.all(Radius.circular(widget.height)), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - decoration: BoxDecoration( - color: (_isLoading || _isTapedDown || _isComplete) && - widget.animate && - widget.buttonColorEnd != null - ? widget.buttonColorEnd - : widget.onSlideComplete != null - ? buttonColor - : buttonColorComplete, - borderRadius: BorderRadius.all(Radius.circular(widget.height)), - ), - height: widget.height, - width: widget.handleWidth, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: _isLoading - ? SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - valueColor: widget.indicatorColor, - strokeWidth: 2, + onTapDown: () { + widget.onTapDown?.call(); + setState(() { + _isTapedDown = true; + }); + }, + onTapUp: () { + setState(() { + _isTapedDown = false; + }); + }, + slidePercentageNeeded: 0.55, + handleWidth: widget.handleWidth, + stayCompleted: widget.stayCompleted, + onSlide: _onSlideComplete, + child: SizedBox( + height: widget.height, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Material( + elevation: 2, + borderRadius: BorderRadius.all(Radius.circular(widget.height)), + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + decoration: BoxDecoration( + color: buttonColor, + borderRadius: BorderRadius.all(Radius.circular(widget.height)), + ), + height: widget.height, + width: widget.handleWidth, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(right: 8), + child: _isLoading + ? SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: buttonColor.onColor, + ), + ) + : Icon( + _isComplete && widget.animate + ? widget.buttonIconEnd ?? ZdsIcons.check_circle + : widget.buttonIcon, + color: buttonColor.onColor, + size: 20, ), - ) - : Icon( - _isComplete && widget.animate - ? widget.buttonIconEnd ?? ZdsIcons.check_circle - : widget.buttonIcon, - color: widget.colors != null ? widget.colors?.on : ZdsColors.white, - size: 20, + ), + Text( + (_isComplete || _isTapedDown || _isLoading) && widget.buttonTextEnd != null + ? widget.buttonTextEnd! + : widget.buttonText, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w500, + color: buttonColor.onColor, ), - ), - Text( - ((_isComplete || _isTapedDown || _isLoading) && widget.buttonTextEnd != null - ? widget.buttonTextEnd! - : widget.buttonText) ?? - '', - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w500, - color: () { - return widget.buttonColor != null - ? computeForeground(widget.buttonColor!) - : colors.on; - }(), - ), - ), - ], + ), + ], + ), ), ), - ), - ], + ], + ), ), ), - ), - if (showDisabledMessage) - Align( - alignment: Alignment.centerRight, - child: SizedBox( - width: 320 - widget.handleWidth, - child: Row( - children: [ - Expanded( - child: Text( - widget.disabledMessage!, - style: Theme.of(context).textTheme.labelMedium, + if (showDisabledMessage) + Align( + alignment: Alignment.centerRight, + child: SizedBox( + width: 320 - widget.handleWidth, + child: Row( + children: [ + Expanded( + child: Text( + widget.disabledMessage!, + style: Theme.of(context).textTheme.labelMedium, + ), ), - ), - ], + ], + ), ), ), - ), - ], + ], + ), ), - ), - ], + ], + ), ); } } diff --git a/lib/src/components/molecules/slidable_list_tile.dart b/lib/src/components/molecules/slidable_list_tile.dart index 1be7ee5..227e09e 100644 --- a/lib/src/components/molecules/slidable_list_tile.dart +++ b/lib/src/components/molecules/slidable_list_tile.dart @@ -88,9 +88,9 @@ class ZdsSlidableListTile extends StatelessWidget { @override Widget build(BuildContext context) { - final Map semanticActions = {}; + final Map semanticActions = {}; - for (final action in [...?actions, ...?leadingActions]) { + for (final ZdsSlidableAction action in [...?actions, ...?leadingActions]) { semanticActions[CustomSemanticsAction(label: action.label)] = () { action.onPressed!(context); }; @@ -106,14 +106,16 @@ class ZdsSlidableListTile extends StatelessWidget { ? ActionPane( motion: const DrawerMotion(), extentRatio: (slideButtonWidth * leadingActions!.length) / width, - children: [for (final action in leadingActions!) _ActionBuilder(action: action)], + children: [ + for (final ZdsSlidableAction action in leadingActions!) _ActionBuilder(action: action), + ], ) : null, endActionPane: actions != null && actions!.isNotEmpty ? ActionPane( motion: const DrawerMotion(), extentRatio: (slideButtonWidth * (actions!.length)) / width, - children: [for (final action in actions!) _ActionBuilder(action: action)], + children: [for (final ZdsSlidableAction action in actions!) _ActionBuilder(action: action)], ) : null, child: Card( @@ -136,15 +138,16 @@ class ZdsSlidableListTile extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DoubleProperty('width', width)); - properties.add(IterableProperty('actions', actions)); - properties.add(IterableProperty('leadingActions', leadingActions)); - properties.add(ColorProperty('backgroundColor', backgroundColor)); - properties.add(DoubleProperty('slideButtonWidth', slideButtonWidth)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(DiagnosticsProperty('slideEnabled', slideEnabled)); - properties.add(DoubleProperty('minHeight', minHeight)); - properties.add(StringProperty('semanticDescription', semanticDescription)); + properties + ..add(DoubleProperty('width', width)) + ..add(IterableProperty('actions', actions)) + ..add(IterableProperty('leadingActions', leadingActions)) + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(DoubleProperty('slideButtonWidth', slideButtonWidth)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(DiagnosticsProperty('slideEnabled', slideEnabled)) + ..add(DoubleProperty('minHeight', minHeight)) + ..add(StringProperty('semanticDescription', semanticDescription)); } } @@ -162,7 +165,7 @@ class _ActionBuilder extends StatefulWidget { } class _ActionBuilderState extends State<_ActionBuilder> { - final _key = GlobalKey(); + final GlobalKey> _key = GlobalKey(); Size _size = Size.zero; Size get size => _size; @@ -185,13 +188,14 @@ class _ActionBuilderState extends State<_ActionBuilder> { @override Widget build(BuildContext context) { + final themeData = Theme.of(context); return FlutterSlidableAction( key: _key, onPressed: widget.action.onPressed, label: size.height < 60 && widget.action.icon != null ? null : widget.action.label, icon: widget.action.icon, - backgroundColor: widget.action.backgroundColor ?? Theme.of(context).colorScheme.background, - foregroundColor: widget.action.foregroundColor ?? Theme.of(context).colorScheme.onBackground, + backgroundColor: widget.action.backgroundColor ?? themeData.colorScheme.background, + foregroundColor: widget.action.foregroundColor ?? themeData.colorScheme.onBackground, autoClose: widget.action.autoclose, spacing: 16, padding: EdgeInsets.zero, @@ -208,6 +212,20 @@ class _ActionBuilderState extends State<_ActionBuilder> { /// Defines an action that will be shown when sliding on a ZdsSlidableListTile. class ZdsSlidableAction { + /// Defines an action that will be shown when sliding on a ZdsSlidableListTile. + /// [label] must not be empty. + /// [backgroundColor], [foregroundColor], and [autoclose] must not be null + ZdsSlidableAction({ + required this.label, + this.onPressed, + this.icon, + this.backgroundColor, + this.foregroundColor, + this.autoclose = true, + this.padding = EdgeInsets.zero, + this.textOverflow, + }) : assert(label.isNotEmpty, 'Label must have content as it acts as the semantic button description'); + /// Function called on press of the widget. final void Function(BuildContext)? onPressed; @@ -239,20 +257,6 @@ class ZdsSlidableAction { /// /// if null, the default value is [TextOverflow.ellipsis] final TextOverflow? textOverflow; - - /// Defines an action that will be shown when sliding on a ZdsSlidableListTile. - /// [label] must not be empty. - /// [backgroundColor], [foregroundColor], and [autoclose] must not be null - ZdsSlidableAction({ - required this.label, - this.onPressed, - this.icon, - this.backgroundColor, - this.foregroundColor, - this.autoclose = true, - this.padding = EdgeInsets.zero, - this.textOverflow, - }) : assert(label.isNotEmpty, 'Label must have content as it acts as the semantic button description'); } // Modified version of SlidableAction from flutter_slidable package @@ -339,7 +343,7 @@ class CustomSlidableAction extends StatelessWidget { @override Widget build(BuildContext context) { - final effectiveForegroundColor = foregroundColor ?? + final Color effectiveForegroundColor = foregroundColor ?? (ThemeData.estimateBrightnessForColor(backgroundColor) == Brightness.light ? Colors.black : Colors.white); return Expanded( @@ -373,13 +377,14 @@ class CustomSlidableAction extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IntProperty('flex', flex)); - properties.add(ColorProperty('backgroundColor', backgroundColor)); - properties.add(ColorProperty('foregroundColor', foregroundColor)); - properties.add(DiagnosticsProperty('autoClose', autoClose)); - properties.add(ObjectFlagProperty.has('onPressed', onPressed)); - properties.add(DiagnosticsProperty('borderRadius', borderRadius)); - properties.add(DiagnosticsProperty('padding', padding)); + properties + ..add(IntProperty('flex', flex)) + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(ColorProperty('foregroundColor', foregroundColor)) + ..add(DiagnosticsProperty('autoClose', autoClose)) + ..add(ObjectFlagProperty.has('onPressed', onPressed)) + ..add(DiagnosticsProperty('borderRadius', borderRadius)) + ..add(DiagnosticsProperty('padding', padding)); } } @@ -445,7 +450,7 @@ class FlutterSlidableAction extends StatelessWidget { @override Widget build(BuildContext context) { - final children = []; + final List children = []; if (icon != null) { children.add( @@ -469,13 +474,13 @@ class FlutterSlidableAction extends StatelessWidget { ); } - final child = children.length == 1 + final Widget child = children.length == 1 ? children.first : Column( mainAxisSize: MainAxisSize.min, - children: [ + children: [ ...children.map( - (child) => Flexible( + (Widget child) => Flexible( child: child, ), ), @@ -497,16 +502,17 @@ class FlutterSlidableAction extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IntProperty('flex', flex)); - properties.add(ColorProperty('backgroundColor', backgroundColor)); - properties.add(ColorProperty('foregroundColor', foregroundColor)); - properties.add(DiagnosticsProperty('autoClose', autoClose)); - properties.add(ObjectFlagProperty.has('onPressed', onPressed)); - properties.add(DiagnosticsProperty('icon', icon)); - properties.add(DoubleProperty('spacing', spacing)); - properties.add(StringProperty('label', label)); - properties.add(DiagnosticsProperty('borderRadius', borderRadius)); - properties.add(DiagnosticsProperty('padding', padding)); - properties.add(EnumProperty('textOverflow', textOverflow)); + properties + ..add(IntProperty('flex', flex)) + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(ColorProperty('foregroundColor', foregroundColor)) + ..add(DiagnosticsProperty('autoClose', autoClose)) + ..add(ObjectFlagProperty.has('onPressed', onPressed)) + ..add(DiagnosticsProperty('icon', icon)) + ..add(DoubleProperty('spacing', spacing)) + ..add(StringProperty('label', label)) + ..add(DiagnosticsProperty('borderRadius', borderRadius)) + ..add(DiagnosticsProperty('padding', padding)) + ..add(EnumProperty('textOverflow', textOverflow)); } } diff --git a/lib/src/components/molecules/stats_card.dart b/lib/src/components/molecules/stats_card.dart index 8f27a7c..a9cca4b 100644 --- a/lib/src/components/molecules/stats_card.dart +++ b/lib/src/components/molecules/stats_card.dart @@ -2,7 +2,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; enum _ListElement { first, middle, last } @@ -15,6 +15,16 @@ enum _ListElement { first, middle, last } /// /// * [ZdsStat], used to define each statistic's properties. class ZdsStatCard extends StatelessWidget { + /// Displays a card with [ZdsStat] values. + const ZdsStatCard({ + required this.stats, + this.subtitle, + super.key, + this.title, + this.isHorizontal, + this.cardVariant = ZdsCardVariant.elevated, + }) : assert(stats.length > 0 && stats.length < 5, 'Only 1 to 4 stats can be used.'), + assert(title?.length != 0, "Title can't be empty if not null."); static const double _padding = 16; static const double _dividerWidth = 0.5; @@ -41,21 +51,10 @@ class ZdsStatCard extends StatelessWidget { /// {@macro card-variant} final ZdsCardVariant? cardVariant; - /// Displays a card with [ZdsStat] values. - const ZdsStatCard({ - required this.stats, - this.subtitle, - super.key, - this.title, - this.isHorizontal, - this.cardVariant = ZdsCardVariant.elevated, - }) : assert(stats.length > 0 && stats.length < 5, 'Only 1 to 4 stats can be used.'), - assert(title?.length != 0, "Title can't be empty if not null."); - bool _isVertical(BuildContext context, BoxConstraints constraints) { - final scale = MediaQuery.of(context).textScaleFactor; - final totalPadding = stats.length * 2 * _padding; - final totalDividers = _dividerWidth * 0.5 * (stats.length - 1); + final double scale = MediaQuery.of(context).textScaleFactor; + final double totalPadding = stats.length * 2 * _padding; + final double totalDividers = _dividerWidth * 0.5 * (stats.length - 1); final double width = ((totalDividers + totalPadding - constraints.maxWidth) / -stats.length) / scale; for (int i = 0; i < stats.length; i++) { final bool description = hasTextOverflow(stats[i].description, Theme.of(context).textTheme.bodySmall!, width); @@ -72,7 +71,7 @@ class ZdsStatCard extends StatelessWidget { } double _columnWidth(BuildContext context) { - final List counter = []; + final List counter = []; for (int i = 0; i < stats.length; i++) { counter.add( textWidth(stats[i]._valueString, Theme.of(context).textTheme.headlineSmall!.copyWith(fontSize: 28)), @@ -83,23 +82,24 @@ class ZdsStatCard extends StatelessWidget { @override Widget build(BuildContext context) { - final Color textColor = Theme.of(context).colorScheme.onSurface; + final themeData = Theme.of(context); + final textColor = themeData.colorScheme.onSurface; return ZdsCard( variant: cardVariant ?? ZdsCardVariant.elevated, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ if (title != null || subtitle != null) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + children: [ if (title != null) Expanded( child: Text( title ?? '', - style: Theme.of(context).textTheme.titleLarge?.copyWith(color: textColor), + style: themeData.textTheme.displaySmall?.copyWith(color: textColor), ), ) else @@ -111,9 +111,9 @@ class ZdsStatCard extends StatelessWidget { child: Text( subtitle ?? '', textAlign: TextAlign.end, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: ZdsColors.greySwatch(context)[1000], - ), + style: themeData.textTheme.bodySmall?.copyWith( + color: Zeta.of(context).colors.textSubtle, + ), ), ) else @@ -121,14 +121,16 @@ class ZdsStatCard extends StatelessWidget { ], ).paddingOnly(bottom: 18), LayoutBuilder( - builder: (context, constraints) { + builder: (BuildContext context, BoxConstraints constraints) { final bool horizontal = isHorizontal ?? !_isVertical(context, constraints); final double horWidth = !horizontal ? _columnWidth(context) : 0; + final zetaColors = Zeta.of(context).colors; + return horizontal ? Row( children: stats .mapIndexed( - (index, stat) => _StatElement( + (int index, ZdsStat stat) => _StatElement( stat: stat, width: (constraints.maxWidth / stats.length) - (_dividerWidth * (stats.length - 1)), type: index == 0 @@ -139,16 +141,16 @@ class ZdsStatCard extends StatelessWidget { ), ) .toList() - .divide(Container(color: ZdsColors.lightGrey, height: 43, width: _dividerWidth)) + .divide(Container(color: zetaColors.borderSubtle, height: 43, width: _dividerWidth)) .toList(), ) : Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Column( children: stats .map( - (stat) => _HorizontalStatElement(statsList: stats, stat: stat, width: horWidth), + (ZdsStat stat) => _HorizontalStatElement(statsList: stats, stat: stat, width: horWidth), ) .toList(), ), @@ -164,35 +166,36 @@ class ZdsStatCard extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IterableProperty('stats', stats)); - properties.add(StringProperty('title', title)); - properties.add(StringProperty('subtitle', subtitle)); - properties.add(DiagnosticsProperty('isHorizontal', isHorizontal)); - properties.add(DiagnosticsProperty('cardVariant', cardVariant)); + properties + ..add(IterableProperty('stats', stats)) + ..add(StringProperty('title', title)) + ..add(StringProperty('subtitle', subtitle)) + ..add(DiagnosticsProperty('isHorizontal', isHorizontal)) + ..add(DiagnosticsProperty('cardVariant', cardVariant)); } } class _HorizontalStatElement extends StatelessWidget { - final ZdsStat stat; - final List statsList; - final double width; - const _HorizontalStatElement({ required this.statsList, required this.stat, required this.width, }); + final ZdsStat stat; + final List statsList; + final double width; + @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.end, - children: [ + children: [ SizedBox( width: width, child: Text( stat._valueString, - style: Theme.of(context).textTheme.bodySmall?.copyWith( + style: Theme.of(context).textTheme.headlineSmall?.copyWith( fontSize: 28, color: stat.color ?? Theme.of(context).colorScheme.onSurface, ), @@ -218,9 +221,10 @@ class _HorizontalStatElement extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('stat', stat)); - properties.add(IterableProperty('statsList', statsList)); - properties.add(DoubleProperty('width', width)); + properties + ..add(DiagnosticsProperty('stat', stat)) + ..add(IterableProperty('statsList', statsList)) + ..add(DoubleProperty('width', width)); } } @@ -243,12 +247,12 @@ class _StatElement extends StatelessWidget { ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Text( stat._valueString, style: Theme.of(context) .textTheme - .headlineMedium! + .headlineSmall! .copyWith(fontSize: 28, color: stat.color ?? Theme.of(context).colorScheme.onSurface), ), const SizedBox(height: 2), @@ -256,7 +260,7 @@ class _StatElement extends StatelessWidget { stat.description, style: Theme.of(context) .textTheme - .titleSmall + .bodySmall ?.copyWith(color: stat.color ?? Theme.of(context).colorScheme.onSurface), maxLines: 1, overflow: TextOverflow.ellipsis, @@ -282,6 +286,9 @@ class _StatElement extends StatelessWidget { /// /// * [ZdsStatCard], used to display multiple ZdsStat. class ZdsStat { + /// Creates a statistic to be used in [ZdsStatCard]. + const ZdsStat({required this.value, required this.description, this.color}); + /// The color with which this stat's value will be displayed in a [ZdsStatCard]. /// /// Defaults to [ColorScheme.onSurface]. @@ -295,8 +302,5 @@ class ZdsStat { /// If using in [ZdsStatCard], this description should be as concise as possible. final String description; - /// Creates a statistic to be used in [ZdsStatCard]. - const ZdsStat({required this.value, required this.description, this.color}); - String get _valueString => value.toString().replaceAll(RegExp(r'([.]*0)(?!.*\d)'), ''); } diff --git a/lib/src/components/molecules/tab_bar.dart b/lib/src/components/molecules/tab_bar.dart index 365614f..6c60546 100644 --- a/lib/src/components/molecules/tab_bar.dart +++ b/lib/src/components/molecules/tab_bar.dart @@ -1,32 +1,44 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/theme/theme.dart'; +import '../../utils/tools.dart'; +import '../atoms/tab.dart'; +import 'responsive_tab_bar.dart'; /// Theme colors for [ZdsTabBar]. enum ZdsTabBarColor { - /// * Background color: `ZetaColors.primary`. - /// * Foreground color: `ZetaColors.onPrimary`. - /// * Unselected foreground color: `ZetaColors.cool.40`. - /// * Indicator color: `ZetaColors.primary.20`. + /// Primary background color, onPrimary foreground color. primary, - /// * Background color: `ZetaColors.cool.90`. - /// * Foreground color: `ZetaColors.cool.20`. - /// * Unselected foreground color: `ZetaColors.cool.40`. - /// * Indicator color: `ZetaColors.primary`. + /// Either dark (Zeta) or ThemeData.background color for background, with respective foreground variants. basic, - /// * Background color: `ZetaColors.surface`. - /// * Foreground color: `ZetaColors.onSurface`. - /// * Unselected foreground color: `ZetaColors.cool.70`. - /// * Indicator color: `ZetaColors.primary`. + /// Surface background color, onSurface foreground color, primary indicator color. surface, + + /// Color will be adaptive to the AppBar theme. Typically used when [ZdsTabBar] or [ZdsResponsiveTabBar] is used + /// as toolbar or bottom widget for any [AppBar] + appBar, } /// Returns a [TabBar] with Zds styling. However, this widget has a number of issues that make it less useful in /// varying screen sizes and resizable screens. It's recommended to instead use [ZdsResponsiveTabBar]. class ZdsTabBar extends StatelessWidget implements PreferredSizeWidget { + /// Makes a [TabBar] with Zds styling applied. It's recommended to instead use [ZdsResponsiveTabBar]. + const ZdsTabBar({ + this.tabs = const [], + super.key, + this.color = ZdsTabBarColor.basic, + this.controller, + this.isScrollable = false, + this.labelPadding = kTabLabelPadding, + this.labelStyle, + this.topSafeArea = true, + this.bottomSafeArea = false, + }); + /// Sets the color scheme for each of the tabs and the tab bar itself. /// /// Defaults to [ZdsTabBarColor.basic]. @@ -56,53 +68,46 @@ class ZdsTabBar extends StatelessWidget implements PreferredSizeWidget { /// Text style for the labels of the tabs. final TextStyle? labelStyle; - /// Makes a [TabBar] with Zds styling applied. It's recommended to instead use [ZdsResponsiveTabBar]. - const ZdsTabBar({ - required this.tabs, - super.key, - this.color = ZdsTabBarColor.primary, - this.controller, - this.isScrollable = false, - this.labelPadding = kTabLabelPadding, - this.labelStyle, - }); + /// Determine's whether component observes safe area at top of the screen. + /// + /// Defaults to true. + /// + /// See also: + /// * [SafeArea]. + final bool topSafeArea; + + /// Determine's whether component observes safe area at bottom of the screen. + /// + /// Defaults to false. + /// + /// See also: + /// * [SafeArea]. + final bool bottomSafeArea; @override Widget build(BuildContext context) { - final appBar = context.findAncestorWidgetOfExactType(); - - final customThemeContainer = Theme.of(context).zdsTabBarThemeData( - context, - hasIcons: hasIcons(tabs), - )[appBar != null ? appBar.color : color]!; - final customTheme = customThemeContainer.customTheme; + final customThemeContainer = ZdsTabBar.buildTheme(context, color: color, hasIcons: hasIcons(tabs)); + final ZdsTabBarThemeData customTheme = customThemeContainer.customTheme; - return Container( - color: (customThemeContainer.customTheme.decoration as BoxDecoration).color, + return DecoratedBox( + decoration: customTheme.decoration, child: SafeArea( - bottom: false, - child: Container( - height: customTheme.height, - decoration: customTheme.decoration, - child: Theme( - data: customThemeContainer.theme, - child: TabBar( - isScrollable: isScrollable, - controller: controller, - labelPadding: labelPadding, - labelStyle: labelStyle, - tabs: tabs - .map( - (item) => Builder( - builder: (context) => IconTheme( - data: IconTheme.of(context).copyWith( - size: customTheme.iconSize, - ), - child: item, - ), - ), - ) - .toList(), + top: topSafeArea, + bottom: bottomSafeArea, + child: Theme( + data: customThemeContainer.theme, + child: SizedBox( + height: customTheme.height, + child: IconTheme( + data: IconTheme.of(context).copyWith(size: customTheme.iconSize), + child: TabBar( + isScrollable: isScrollable, + indicatorWeight: 1, + controller: controller, + labelPadding: labelPadding, + labelStyle: labelStyle, + tabs: tabs, + ), ), ), ), @@ -118,10 +123,99 @@ class ZdsTabBar extends StatelessWidget implements PreferredSizeWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(EnumProperty('color', color)); - properties.add(DiagnosticsProperty('controller', controller)); - properties.add(DiagnosticsProperty('isScrollable', isScrollable)); - properties.add(DiagnosticsProperty('labelPadding', labelPadding)); - properties.add(DiagnosticsProperty('labelStyle', labelStyle)); + properties + ..add(EnumProperty('color', color)) + ..add(DiagnosticsProperty('controller', controller)) + ..add(DiagnosticsProperty('isScrollable', isScrollable)) + ..add(DiagnosticsProperty('labelPadding', labelPadding)) + ..add(DiagnosticsProperty('labelStyle', labelStyle)) + ..add(DiagnosticsProperty('topSafeArea', topSafeArea)) + ..add(DiagnosticsProperty('bottomSafeArea', bottomSafeArea)); + } + + /// Generates theme for [ZdsTabBar]. + static ZdsTabBarStyleContainer buildTheme( + BuildContext context, { + required bool hasIcons, + required ZdsTabBarColor color, + Color? indicatorColor, + }) { + final zetaColors = Zeta.of(context).colors; + switch (color) { + case ZdsTabBarColor.primary: + return _tabBarStyle( + context, + hasIcons, + background: zetaColors.primary, + indicator: zetaColors.primary.onColor, + selectedText: zetaColors.primary.onColor, + unselectedText: zetaColors.primary.onColor.withOpacity(0.7), + ); + case ZdsTabBarColor.basic: + return _tabBarStyle( + context, + hasIcons, + background: zetaColors.surfaceTertiary, + indicator: zetaColors.primary, + selectedText: zetaColors.textDefault, + unselectedText: zetaColors.textSubtle, + ); + case ZdsTabBarColor.surface: + return _tabBarStyle( + context, + hasIcons, + background: zetaColors.surfacePrimary, + indicator: zetaColors.primary, + selectedText: zetaColors.textDefault, + unselectedText: zetaColors.textSubtle, + ); + case ZdsTabBarColor.appBar: + final appBarTheme = Theme.of(context).appBarTheme; + return _tabBarStyle( + context, + hasIcons, + background: appBarTheme.backgroundColor ?? zetaColors.surfacePrimary, + indicator: appBarTheme.foregroundColor ?? zetaColors.primary, + selectedText: appBarTheme.foregroundColor ?? zetaColors.textDefault, + unselectedText: appBarTheme.foregroundColor?.withOpacity(0.7) ?? zetaColors.textSubtle, + ); + } + } + + /// Builds [ZdsTabBarStyleContainer]. Defaults to primary color. + static ZdsTabBarStyleContainer _tabBarStyle( + BuildContext context, + bool hasIcons, { + required Color selectedText, + required Color background, + required Color unselectedText, + required Color indicator, + }) { + final double height = hasIcons ? 56.0 : 48.0; + final ThemeData theme = Theme.of(context); + + final TabBarTheme tabBarTheme = theme.tabBarTheme.copyWith(indicatorSize: TabBarIndicatorSize.tab); + final TextStyle? labelStyle = hasIcons ? theme.textTheme.bodyXSmall : theme.textTheme.bodyLarge; + + return ZdsTabBarStyleContainer( + customTheme: ZdsTabBarThemeData( + decoration: BoxDecoration(color: background), + height: height, + ), + theme: theme.copyWith( + tabBarTheme: tabBarTheme.copyWith( + labelStyle: labelStyle, + unselectedLabelStyle: labelStyle, + unselectedLabelColor: unselectedText, + labelColor: selectedText, + indicator: UnderlineTabIndicator( + borderSide: BorderSide( + width: 3, + color: indicator, + ), + ), + ), + ), + ); } } diff --git a/lib/src/components/molecules/tag.dart b/lib/src/components/molecules/tag.dart index ae7ff6c..8549ff1 100644 --- a/lib/src/components/molecules/tag.dart +++ b/lib/src/components/molecules/tag.dart @@ -1,18 +1,18 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Tag colors /// -/// If `filled`, foreground will always be [ZdsColors.white] and background will be the selected color +/// If `filled`, foreground will always be computed based on background will be the selected color /// /// Otherwise, the background will the same color, but with 10% opacity. enum ZdsTagColor { - /// [ZdsColors.red]. + /// [ColorScheme.error]. error, - /// [ZdsColors.orange]. + /// [ZetaColors.orange]. alert, /// Primary color. @@ -21,10 +21,10 @@ enum ZdsTagColor { /// Secondary color. secondary, - /// [ZdsColors.green]. + /// [ZetaColors.green]. success, - /// [ZdsColors.darkGrey] + /// [ZetaColors.warm] basic, } @@ -41,6 +41,28 @@ enum ZdsTagColor { /// * Setting [rectangular] as true, typically with [prefix], typically used to indicate status, e.g pending, approved and declined. /// * Setting [rounded] and [rectangular] as false, typically used to indicate status and to allow actions on the tag with [onClose]. class ZdsTag extends StatelessWidget { + /// Tag item that can have a close/remove button. + /// + /// When [unrestrictedSize] is true, the tag will size itself to its child's size. This is useful for bigger fonts + /// or non-text children like images and such. + const ZdsTag({ + super.key, + this.rounded = false, + this.rectangular = false, + this.filled = false, + this.prefix, + this.color = ZdsTagColor.basic, + this.customColor, + this.child, + this.onClose, + this.unrestrictedSize = false, + this.customBackgroundColor, + }) : assert( + prefix != null && (rounded || rectangular) || prefix == null, + 'If prefix is not null, rounded must be true', + ), + assert(filled && prefix == null || !filled, 'If filled is true, prefix must be null'); + /// Whether to have completely rounded ends (pill shape) or to have a rectangle shape /// /// If [prefix] is not null, this must be true. Defaults to false @@ -52,7 +74,7 @@ class ZdsTag extends StatelessWidget { final bool rectangular; /// Whether the [color] or [customColor] will act as the background color (with the foreground color being - /// [ZdsColors.white]), or as the foreground color (with the background color being the color set to 10% opacity). + /// be computed based on effective background), or as the foreground color (with the background color being the color set to 10% opacity). /// /// If true, [prefix] must be null. Defaults to false. final bool filled; @@ -97,31 +119,19 @@ class ZdsTag extends StatelessWidget { /// Defaults to false. final bool unrestrictedSize; - /// Tag item that can have a close/remove button. - /// - /// When [unrestrictedSize] is true, the tag will size itself to its child's size. This is useful for bigger fonts - /// or non-text children like images and such. - const ZdsTag({ - super.key, - this.rounded = false, - this.rectangular = false, - this.filled = false, - this.prefix, - this.color = ZdsTagColor.basic, - this.customColor, - this.child, - this.onClose, - this.unrestrictedSize = false, - this.customBackgroundColor, - }) : assert( - prefix != null && (rounded || rectangular) || prefix == null, - 'If prefix is not null, rounded must be true', - ), - assert(filled && prefix == null || !filled, 'If filled is true, prefix must be null'); - @override Widget build(BuildContext context) { - final colors = _resolveColor(context, color); + final zetaColors = Zeta.of(context).colors; + + Color fgColor = customColor ?? _resolveFgColor(zetaColors, color); + Color bgColor; + + if (filled) { + bgColor = fgColor; + fgColor = fgColor.onColor; + } else { + bgColor = customBackgroundColor ?? _resolveBgColor(zetaColors, color); + } final double height = onClose == null ? rounded @@ -134,14 +144,14 @@ class ZdsTag extends StatelessWidget { return Row( mainAxisSize: MainAxisSize.min, - children: [ + children: [ MergeSemantics( child: Padding( padding: const EdgeInsets.all(2), child: Container( constraints: BoxConstraints(minHeight: height, maxHeight: unrestrictedSize ? double.infinity : height), decoration: BoxDecoration( - color: colors.last, + color: bgColor, borderRadius: BorderRadius.circular( rectangular ? rectangularBorderRadius @@ -151,15 +161,15 @@ class ZdsTag extends StatelessWidget { ), ), child: Row( - children: [ + children: [ if (prefix != null) ZdsIndex( useBoxDecoration: !rectangular, - color: colors.first, + color: fgColor, child: prefix, ), DefaultTextStyle( - style: Theme.of(context).textTheme.bodySmall!.copyWith(color: colors.first), + style: Theme.of(context).textTheme.bodySmall!.copyWith(color: fgColor), child: child ?? const SizedBox(), ).paddingInsets(padding), if (onClose != null) @@ -169,13 +179,13 @@ class ZdsTag extends StatelessWidget { child: ConstrainedBox( constraints: const BoxConstraints(minHeight: 48, minWidth: 48), child: InkResponse( - highlightColor: colors.last, - splashColor: colors.last, + highlightColor: bgColor, + splashColor: bgColor, radius: height / 1.5, onTap: onClose, child: Icon( ZdsIcons.close, - color: colors.first, + color: fgColor, size: 16, ), ), @@ -190,53 +200,51 @@ class ZdsTag extends StatelessWidget { ); } - List _resolveColor(BuildContext context, ZdsTagColor color) { - final Color foregroundColor = customColor ?? _tagColors(context, color); - - if (filled) { - return [ZdsColors.white, foregroundColor]; - } - - Color background = customBackgroundColor ?? foregroundColor.withLight(0.1); - - if (color == ZdsTagColor.secondary) { - background = ZdsColors.secondarySwatch(context).shade200; - } - - if (color == ZdsTagColor.success) { - background = ZdsColors.greenSwatch['light']!; + Color _resolveFgColor(ZetaColors zetaColors, ZdsTagColor tagColor) { + switch (tagColor) { + case ZdsTagColor.error: + return zetaColors.negative; + case ZdsTagColor.alert: + return zetaColors.warning; + case ZdsTagColor.primary: + return zetaColors.primary; + case ZdsTagColor.secondary: + return zetaColors.secondary; + case ZdsTagColor.success: + return zetaColors.positive; + case ZdsTagColor.basic: + return zetaColors.warm.shade80; } - - return [foregroundColor, background]; } - Color _tagColors(BuildContext context, ZdsTagColor tagColor) { + Color _resolveBgColor(ZetaColors zetaColors, ZdsTagColor tagColor) { switch (tagColor) { case ZdsTagColor.error: - return ZdsColors.red; + return zetaColors.error.surface; case ZdsTagColor.alert: - return ZdsColors.orange; + return zetaColors.orange.surface; case ZdsTagColor.primary: - return Theme.of(context).colorScheme.primary; + return zetaColors.primary.surface; case ZdsTagColor.secondary: - return Theme.of(context).colorScheme.secondary; + return zetaColors.secondary.surface; case ZdsTagColor.success: - return ZdsColors.green; + return zetaColors.green.surface; case ZdsTagColor.basic: - return ZdsColors.darkGrey; + return zetaColors.warm.shade30; } } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('rounded', rounded)); - properties.add(DiagnosticsProperty('rectangular', rectangular)); - properties.add(DiagnosticsProperty('filled', filled)); - properties.add(EnumProperty('color', color)); - properties.add(ColorProperty('customColor', customColor)); - properties.add(ColorProperty('customBackgroundColor', customBackgroundColor)); - properties.add(ObjectFlagProperty.has('onClose', onClose)); - properties.add(DiagnosticsProperty('unrestrictedSize', unrestrictedSize)); + properties + ..add(DiagnosticsProperty('rounded', rounded)) + ..add(DiagnosticsProperty('rectangular', rectangular)) + ..add(DiagnosticsProperty('filled', filled)) + ..add(EnumProperty('color', color)) + ..add(ColorProperty('customColor', customColor)) + ..add(ColorProperty('customBackgroundColor', customBackgroundColor)) + ..add(ObjectFlagProperty.has('onClose', onClose)) + ..add(DiagnosticsProperty('unrestrictedSize', unrestrictedSize)); } } diff --git a/lib/src/components/molecules/toast.dart b/lib/src/components/molecules/toast.dart index a1f0ffa..9b05bfa 100644 --- a/lib/src/components/molecules/toast.dart +++ b/lib/src/components/molecules/toast.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; // TODO(colors): Add zeta @@ -19,6 +19,9 @@ enum ZdsToastColors { /// * `warning` = yellow background /grey foreground warning, + /// * `info` = purple background / grey foreground + info, + /// * `error` = red background / grey foreground error, @@ -53,6 +56,17 @@ enum ZdsToastColors { /// /// * [ZdsSnackBarExtension.showZdsToast], used to display a toast message on screen. class ZdsToast extends StatelessWidget implements PreferredSizeWidget { + /// The contents of a toast, typically used with [ZdsSnackBarExtension.showZdsToast]. + const ZdsToast({ + super.key, + this.leading, + this.title, + this.actions, + ZdsToastColors? color, + this.rounded = true, + this.multiLine = false, + }) : color = color ?? ZdsToastColors.primary; + /// An icon that will be shown before the [title]. /// /// Typically an [Icon]. @@ -71,7 +85,7 @@ class ZdsToast extends StatelessWidget implements PreferredSizeWidget { /// Determines foreground and background color of toast to comply with design rules. /// /// View [ZdsToastColors] for more details. - final ZdsToastColors? color; + final ZdsToastColors color; /// Whether this toast will have rounded corners. /// @@ -83,44 +97,55 @@ class ZdsToast extends StatelessWidget implements PreferredSizeWidget { /// Defaults to false. final bool multiLine; - /// The contents of a toast, typically used with [ZdsSnackBarExtension.showZdsToast]. - const ZdsToast({ - super.key, - this.leading, - this.title, - this.actions, - this.color = ZdsToastColors.primary, - this.rounded = true, - this.multiLine = false, - }); + Color _backgroundColor(ZetaColors colors, ZdsToastColors toastColor) { + switch (toastColor) { + case ZdsToastColors.success: + return colors.positive.shade10; + case ZdsToastColors.warning: + return colors.warning.shade10; + case ZdsToastColors.info: + return colors.info.shade10; + case ZdsToastColors.error: + return colors.error.shade10; + case ZdsToastColors.primary: + return colors.primary.shade10; + case ZdsToastColors.dark: + return colors.textDefault; + } + } - Color _backgroundColor(BuildContext context, ZdsToastColors toastColor) { + Color _iconColor(ZetaColors colors, ZdsToastColors toastColor) { switch (toastColor) { case ZdsToastColors.success: - return ZdsColors.green.withLight(0.15); + return colors.green.shade60; case ZdsToastColors.warning: - return ZdsColors.yellow.withLight(0.15); + return colors.orange.shade60; + case ZdsToastColors.info: + return colors.info.shade60; case ZdsToastColors.error: - return ZdsColors.red.withLight(0.15); + return colors.error.shade60; case ZdsToastColors.primary: - return ZdsColors.secondarySwatch(context).shade100; + return colors.primary.shade60; case ZdsToastColors.dark: - return ZdsColors.greySwatch(context)[1200]!; + return colors.textInverse; } } - Color _foregroundColor(ZdsToastColors toastColor) { + Color _foregroundColor(ZetaColors colors, ZdsToastColors toastColor) { if (toastColor == ZdsToastColors.dark) { - return ZdsColors.white; + return colors.textInverse; + } else { + return colors.textDefault; } - return ZdsColors.darkGrey; } @override Widget build(BuildContext context) { + final zetaColors = Zeta.of(context).colors; + final foregroundColor = _foregroundColor(zetaColors, color); return Column( mainAxisSize: MainAxisSize.min, - children: [ + children: [ Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(horizontal: rounded ? 8.0 : 0), @@ -136,35 +161,38 @@ class ZdsToast extends StatelessWidget implements PreferredSizeWidget { : 0, ), ), - color: _backgroundColor(context, color!), + color: _backgroundColor(zetaColors, color), child: Container( constraints: const BoxConstraints(minHeight: kToastHeight), padding: EdgeInsets.only(left: 18, top: multiLine ? 14 : 0, bottom: multiLine ? 14 : 0, right: 10), - child: IconTheme( - data: IconThemeData(color: _foregroundColor(color!)), - child: Row( - children: [ - if (leading != null) leading!, - Expanded( - child: () { - if (title != null) { - return DefaultTextStyle( - style: Theme.of(context).textTheme.bodyLarge!.copyWith(color: _foregroundColor(color!)), + child: Row( + children: [ + if (leading != null) + IconTheme( + data: IconThemeData(color: _iconColor(zetaColors, color)), + child: leading!, + ), + Expanded( + child: title != null + ? DefaultTextStyle( + style: safeTextStyle(Theme.of(context).textTheme.bodyLarge).copyWith( + color: foregroundColor, + ), overflow: TextOverflow.ellipsis, maxLines: multiLine ? 5 : 1, child: title!, - ); - } - return const SizedBox(); - }(), - ), - if (actions != null) - Row( + ) + : const SizedBox.shrink(), + ), + if (actions != null && actions!.isNotEmpty) + IconTheme( + data: IconThemeData(color: foregroundColor), + child: Row( mainAxisSize: MainAxisSize.min, children: actions!.divide(const SizedBox(width: 10)).toList(), ), - ].divide(const SizedBox(width: 10)).toList(), - ), + ), + ].divide(const SizedBox(width: 10)).toList(), ), ), ), @@ -175,12 +203,14 @@ class ZdsToast extends StatelessWidget implements PreferredSizeWidget { @override Size get preferredSize => const Size.fromHeight(kToastHeight); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(EnumProperty('color', color)); - properties.add(DiagnosticsProperty('rounded', rounded)); - properties.add(DiagnosticsProperty('multiLine', multiLine)); + properties + ..add(EnumProperty('color', color)) + ..add(DiagnosticsProperty('rounded', rounded)) + ..add(DiagnosticsProperty('multiLine', multiLine)); } } @@ -206,7 +236,7 @@ extension ZdsSnackBarExtension on ScaffoldMessengerState { return showSnackBar( SnackBar( content: toast, - backgroundColor: ZdsColors.transparent, + backgroundColor: Colors.transparent, elevation: 0, behavior: SnackBarBehavior.fixed, padding: padding, diff --git a/lib/src/components/molecules/toolbar.dart b/lib/src/components/molecules/toolbar.dart index 8decba3..634db23 100644 --- a/lib/src/components/molecules/toolbar.dart +++ b/lib/src/components/molecules/toolbar.dart @@ -1,8 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// A toolbar, used for additional actions that do not fit in the app bar. /// @@ -20,6 +19,16 @@ import '../../../zds_flutter.dart'; /// /// * [ZdsAppBar], which allows to put a widget below it. class ZdsToolbar extends StatelessWidget { + /// A toolbar which can be used for additional actions that do not fit in the app bar. + const ZdsToolbar({ + super.key, + this.title, + this.subtitle, + this.actions, + this.child, + this.backgroundColor, + }); + /// The toolbar's title or main widget. /// /// Typically a [Text]. @@ -41,36 +50,26 @@ class ZdsToolbar extends StatelessWidget { /// The background color for this ToolBar. Defaults to [ColorScheme.primary] final Color? backgroundColor; - /// A toolbar which can be used for additional actions that do not fit in the app bar. - const ZdsToolbar({ - super.key, - this.title, - this.subtitle, - this.actions, - this.child, - this.backgroundColor, - }); - @override Widget build(BuildContext context) { - final theme = Theme.of(context); + final ThemeData theme = Theme.of(context); + final effectiveBackground = backgroundColor ?? theme.appBarTheme.backgroundColor ?? theme.colorScheme.primary; + final effectiveForeground = effectiveBackground.onColor; return IconTheme( - data: theme.primaryIconTheme, + data: theme.primaryIconTheme.copyWith(color: effectiveForeground), child: Material( - color: backgroundColor ?? theme.colorScheme.primary, + color: effectiveBackground, child: SafeArea( + bottom: false, child: Column( - children: [ + children: [ Container( constraints: const BoxConstraints(minHeight: 56), alignment: Alignment.center, - // decoration: BoxDecoration( - // border: Border(top: BorderSide(width: 1, color: theme.colorScheme.onPrimary.withOpacity(0.1))), - // ), child: Row( crossAxisAlignment: _getCrossAxisAlignment, textBaseline: TextBaseline.alphabetic, - children: [ + children: [ Expanded( child: Container( padding: _resolvedContentPadding(context), @@ -79,19 +78,21 @@ class ZdsToolbar extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, - children: [ + children: [ if (title != null) Container( constraints: const BoxConstraints(minHeight: 43), alignment: Alignment.bottomLeft, child: DefaultTextStyle( - style: theme.primaryTextTheme.titleLarge!, + style: safeTextStyle(theme.primaryTextTheme.headlineMedium).copyWith( + color: effectiveForeground, + ), maxLines: 1, overflow: TextOverflow.ellipsis, child: title!, ), ), - if (subtitle != null) ...[ + if (subtitle != null) ...[ const SizedBox(height: 8), Container( constraints: const BoxConstraints(minHeight: 43), @@ -99,11 +100,9 @@ class ZdsToolbar extends StatelessWidget { child: DefaultTextStyle( maxLines: 1, overflow: TextOverflow.ellipsis, - style: () { - return theme.primaryTextTheme.titleSmall!.copyWith( - color: ZetaColors.of(context).onPrimary.withOpacity(0.8), - ); - }(), + style: safeTextStyle(theme.primaryTextTheme.titleSmall).copyWith( + color: effectiveForeground.withOpacity(0.8), + ), child: subtitle!, ), ), @@ -135,15 +134,16 @@ class ZdsToolbar extends StatelessWidget { } EdgeInsets _resolvedContentPadding(BuildContext context) { - final contentPadding = Theme.of(context).zdsToolbarThemeData.contentPadding; + final EdgeInsets contentPadding = kZdsToolbarTheme.contentPadding; return EdgeInsets.only( - left: title is DateRange ? 0 : contentPadding.left, + left: title is ZdsDateRange ? 0 : contentPadding.left, right: contentPadding.right, ); } bool get _expandedLayout => subtitle != null && title != null; + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); diff --git a/lib/src/components/molecules/vertical_nav.dart b/lib/src/components/molecules/vertical_nav.dart index 42301ef..3d7689b 100644 --- a/lib/src/components/molecules/vertical_nav.dart +++ b/lib/src/components/molecules/vertical_nav.dart @@ -1,7 +1,9 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/assets/icons.dart'; +import '../organisms/bottom_tab_bar.dart'; /// A [ZdsVerticalNav] used to switch between different views. Should primarily be used for tablet views and larger screens. /// @@ -20,6 +22,22 @@ import '../../../zds_flutter.dart'; /// ) /// ``` class ZdsVerticalNav extends StatefulWidget { + /// Creates a vertical navigation bar + /// + /// [items] can't be null. [currentIndex]'s value must be equal or greater than 0, and smaller than [items].length. + const ZdsVerticalNav({ + required this.items, + required this.currentIndex, + this.actions, + this.barWidth = 48, + this.itemHeight = 53, + super.key, + this.onTap, + }) : assert( + 0 <= currentIndex && currentIndex < items.length, + 'currentIndex must not be greater than the number of items', + ); + /// The [ZdsNavItem] list that will be displayed at the **bottom** of the component. Each item should be linked to a separate view. final List items; @@ -46,32 +64,18 @@ class ZdsVerticalNav extends StatefulWidget { /// Defaults to 53 final double itemHeight; - /// Creates a vertical navigation bar - /// - /// [items] can't be null. [currentIndex]'s value must be equal or greater than 0, and smaller than [items].length. - const ZdsVerticalNav({ - required this.items, - required this.currentIndex, - this.actions, - this.barWidth = 48, - this.itemHeight = 53, - super.key, - this.onTap, - }) : assert( - 0 <= currentIndex && currentIndex < items.length, - 'currentIndex must not be greater than the number of items', - ); - @override State createState() => _ZdsVerticalNavState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IterableProperty('items', items)); - properties.add(IntProperty('currentIndex', currentIndex)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(DoubleProperty('barWidth', barWidth)); - properties.add(DoubleProperty('itemHeight', itemHeight)); + properties + ..add(IterableProperty('items', items)) + ..add(IntProperty('currentIndex', currentIndex)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(DoubleProperty('barWidth', barWidth)) + ..add(DoubleProperty('itemHeight', itemHeight)); } } @@ -80,8 +84,8 @@ class _ZdsVerticalNavState extends State { @override Widget build(BuildContext context) { - final itemsWidget = Stack( - children: [ + final Stack itemsWidget = Stack( + children: [ if (!isExpanded) AnimatedPositioned( curve: Curves.ease, @@ -93,7 +97,7 @@ class _ZdsVerticalNavState extends State { ), Column( children: widget.items.map( - (item) { + (ZdsNavItem item) { final bool selected = widget.currentIndex == widget.items.indexOf(item); return MergeSemantics( child: Semantics( @@ -117,7 +121,7 @@ class _ZdsVerticalNavState extends State { data: IconThemeData( color: selected ? Theme.of(context).colorScheme.secondary - : ZdsColors.greySwatch(context)[1000], + : Zeta.of(context).colors.iconSubtle, size: 24, ), child: item.icon, @@ -135,23 +139,25 @@ class _ZdsVerticalNavState extends State { ); return LayoutBuilder( - builder: (context, constraints) { + builder: (BuildContext context, BoxConstraints constraints) { + final actions = widget.actions; final bool isTooShort = - (((widget.actions?.length ?? 0) + widget.items.length) * widget.itemHeight) + (2 * widget.itemHeight) + 4 >= + (((actions?.length ?? 0) + widget.items.length) * widget.itemHeight) + (2 * widget.itemHeight) + 4 >= (constraints.minHeight != 0 ? constraints.minHeight : constraints.maxHeight); - final actionsWidget = widget.actions != null + final themeData = Theme.of(context); + final Widget actionsWidget = actions != null ? IconTheme( - data: IconThemeData(color: Theme.of(context).colorScheme.secondary, size: 24), + data: IconThemeData(color: themeData.colorScheme.secondary, size: 24), child: SingleChildScrollView( child: Column( - children: widget.actions! + children: actions .map( - (action) => Column( - children: [ + (Widget action) => Column( + children: [ action, - if (widget.actions!.indexOf(action) != widget.actions!.length - 1) - Divider(color: ZdsColors.greySwatch(context)[100]), + if (actions.indexOf(action) != actions.length - 1) + Divider(color: Zeta.of(context).colors.borderSubtle), ], ), ) @@ -164,24 +170,24 @@ class _ZdsVerticalNavState extends State { return Container( width: widget.barWidth, decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - boxShadow: [ + color: themeData.colorScheme.surface, + boxShadow: [ BoxShadow( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.25), - blurRadius: 2, - offset: const Offset(-1, 0), + color: themeData.colorScheme.onSurface.withOpacity(0.25), + blurRadius: 1, + offset: const Offset(1, 0), ), ], ), padding: const EdgeInsets.only(bottom: 4), child: Material( child: Stack( - children: [ + children: [ if (isTooShort) Positioned( top: 0, child: IconTheme( - data: IconThemeData(color: Theme.of(context).colorScheme.secondary, size: 24), + data: IconThemeData(color: themeData.colorScheme.secondary, size: 24), child: IconButton( onPressed: () => setState(() => isExpanded = !isExpanded), icon: Icon(isExpanded ? ZdsIcons.back : ZdsIcons.more_vert), @@ -218,13 +224,14 @@ class _ZdsVerticalNavState extends State { } class _SelectedBackground extends StatelessWidget { + const _SelectedBackground({required this.width, required this.height}); + final double width; final double height; - const _SelectedBackground({required this.width, required this.height}); - @override Widget build(BuildContext context) { + final themeData = Theme.of(context); return SizedBox( width: width, height: height, @@ -233,17 +240,18 @@ class _SelectedBackground extends StatelessWidget { padding: const EdgeInsets.only(left: 1), decoration: BoxDecoration( gradient: LinearGradient( - colors: [Theme.of(context).colorScheme.background, Theme.of(context).colorScheme.surface], + colors: [themeData.colorScheme.background, themeData.colorScheme.surface], ), borderRadius: const BorderRadius.only( topLeft: Radius.circular(4), bottomLeft: Radius.circular(4), ), - boxShadow: [ + boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.25), - blurRadius: 2, - offset: const Offset(-2, 1), + color: themeData.cardTheme.shadowColor ?? Colors.black.withOpacity(0.25), + blurRadius: 1, + spreadRadius: 1, + offset: const Offset(-1, 1), ), ], ), @@ -254,7 +262,8 @@ class _SelectedBackground extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DoubleProperty('width', width)); - properties.add(DoubleProperty('height', height)); + properties + ..add(DoubleProperty('width', width)) + ..add(DoubleProperty('height', height)); } } diff --git a/lib/src/components/organisms.dart b/lib/src/components/organisms.dart index 84abc9d..2d85f89 100644 --- a/lib/src/components/organisms.dart +++ b/lib/src/components/organisms.dart @@ -9,7 +9,7 @@ export 'organisms/date_range_picker_tile.dart'; export 'organisms/day_picker.dart'; export 'organisms/file_picker/file_picker.dart'; export 'organisms/file_preview.dart'; -export 'organisms/image_editor.dart'; +export 'organisms/html_preview/html_container.dart'; export 'organisms/image_picker.dart'; export 'organisms/infinite_list.dart'; export 'organisms/list_group.dart'; @@ -18,6 +18,7 @@ export 'organisms/modal.dart'; export 'organisms/navigation_menu.dart'; export 'organisms/profile.dart'; export 'organisms/properties_list.dart'; +export 'organisms/quill_editor/quill.dart'; export 'organisms/radio_list.dart'; export 'organisms/search_app_bar.dart'; export 'organisms/tab_scaffold.dart'; diff --git a/lib/src/components/organisms/app_bar.dart b/lib/src/components/organisms/app_bar.dart index acde915..1aed65a 100644 --- a/lib/src/components/organisms/app_bar.dart +++ b/lib/src/components/organisms/app_bar.dart @@ -2,9 +2,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/semantics.dart'; import 'package:flutter/services.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// An app bar with Zds styling. /// @@ -29,12 +28,26 @@ import '../../../zds_flutter.dart'; /// * [ZdsPopupMenu], typically used in [actions] to display a kebab menu for further actions that would pollute /// the appbar if they were all shown. class ZdsAppBar extends StatelessWidget implements PreferredSizeWidget { + /// Creates an appbar that is typically shown at the top of the screen. + const ZdsAppBar({ + super.key, + this.leading, + this.title, + this.actions, + this.subtitle, + this.icon, + this.bottom, + this.systemUiOverlayStyle, + this.applyTopSafeArea = true, + this.color = ZdsTabBarColor.appBar, + }); + /// The widget shown at the start of the appbar. Typically an [IconButton]. /// /// If null and the [Navigator]'s stack can pop, a back button will be shown by default. final Widget? leading; - /// The appbar's main text. Typically a [Text] widget, it is usually used to show the page's name. + /// The appBar's main text. Typically a [Text] widget, it is usually used to show the page's name. final Widget? title; /// The widget that will be shown below the [title]. Typically a [Text] widget, it is usually used to display @@ -66,34 +79,35 @@ class ZdsAppBar extends StatelessWidget implements PreferredSizeWidget { /// See [ZdsTabBarColor]. final ZdsTabBarColor color; - /// Creates an appbar that is typically shown at the top of the screen. - const ZdsAppBar({ - super.key, - this.leading, - this.title, - this.actions, - this.subtitle, - this.icon, - this.bottom, - this.systemUiOverlayStyle, - this.color = ZdsTabBarColor.primary, - }); + /// (`applyTopSafeArea`) Determines if the top safe area should be applied to the `ZdsAppBar` or not. + /// + /// Set to `true` if you want your application to eliminate any disruptive + /// elements present at the top of the screen like the notch on the iPhone X + /// for the `ZdsAppBar`. It is recommended to leave this as `true` for better UI. + /// + /// If set to `false`, disruptive elements at the top of the screen will not be + /// accounted for and you might have some UI elements hidden behind those disruptions. + /// + /// This is a final value, meaning that once set, it cannot be changed. + /// + /// Defaults to `true` + final bool applyTopSafeArea; @override Widget build(BuildContext context) { - final theme = Theme.of(context); - final ZetaColors colors = ZetaColors.of(context); - final AppBarTheme appBarTheme = Theme.of(context).buildAppBarTheme(colors)[color]!; + final ThemeData theme = Theme.of(context); + final AppBarTheme appBarTheme = buildTheme(context, color); - return AnnotatedRegion( + return AnnotatedRegion( value: systemUiOverlayStyle ?? appBarTheme.systemOverlayStyle ?? SystemUiOverlayStyle.dark, sized: false, child: Material( color: appBarTheme.backgroundColor, child: SafeArea( + top: applyTopSafeArea, bottom: false, child: Column( - children: [ + children: [ SizedBox( height: _toolbarHeight, child: IconTheme( @@ -101,7 +115,7 @@ class ZdsAppBar extends StatelessWidget implements PreferredSizeWidget { child: Padding( padding: EdgeInsets.symmetric(horizontal: icon == null ? 24 : 12), child: Row( - children: [ + children: [ Semantics( sortKey: const OrdinalSortKey(2), child: _resolvedLeading(context), @@ -119,7 +133,7 @@ class ZdsAppBar extends StatelessWidget implements PreferredSizeWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, - children: [ + children: [ if (title != null) title!, if (title != null && subtitle != null) const SizedBox(height: 4), if (subtitle != null) @@ -156,7 +170,9 @@ class ZdsAppBar extends StatelessWidget implements PreferredSizeWidget { Size get preferredSize => Size.fromHeight(_toolbarHeight + _bottomHeight); double get _bottomHeight => bottom?.preferredSize.height ?? 0; + double get _toolbarHeight => kZdsToolbarHeight; + Widget _resolvedLeading(BuildContext context) { if (leading != null) return leading!; @@ -170,7 +186,60 @@ class ZdsAppBar extends StatelessWidget implements PreferredSizeWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('systemUiOverlayStyle', systemUiOverlayStyle)); - properties.add(EnumProperty('color', color)); + properties + ..add(DiagnosticsProperty('systemUiOverlayStyle', systemUiOverlayStyle)) + ..add(EnumProperty('color', color)) + ..add(DiagnosticsProperty('applyTopSafeArea', applyTopSafeArea)); + } + + /// Builds theme variants for [ZdsAppBar]. + /// + /// See also + /// * [ZdsTabBarColor]. + static AppBarTheme buildTheme(BuildContext context, ZdsTabBarColor color) { + final zetaColors = Zeta.of(context).colors; + switch (color) { + case ZdsTabBarColor.appBar: + return Theme.of(context).appBarTheme; + case ZdsTabBarColor.primary: + final fgColor = zetaColors.primary.onColor; + final bgColor = zetaColors.primary; + return AppBarTheme( + systemOverlayStyle: computeSystemOverlayStyle(bgColor), + backgroundColor: bgColor, + foregroundColor: fgColor, + centerTitle: false, + titleSpacing: 0, + elevation: 0.5, + iconTheme: IconThemeData(color: fgColor), + actionsIconTheme: IconThemeData(color: fgColor), + ); + case ZdsTabBarColor.basic: + final fgColor = zetaColors.textDefault; + final bgColor = zetaColors.surfaceTertiary; + return AppBarTheme( + systemOverlayStyle: computeSystemOverlayStyle(bgColor), + backgroundColor: bgColor, + foregroundColor: fgColor, + centerTitle: false, + titleSpacing: 0, + elevation: 0.5, + iconTheme: IconThemeData(color: fgColor), + actionsIconTheme: IconThemeData(color: fgColor), + ); + case ZdsTabBarColor.surface: + final fgColor = zetaColors.textDefault; + final bgColor = zetaColors.surfacePrimary; + return AppBarTheme( + systemOverlayStyle: computeSystemOverlayStyle(bgColor), + backgroundColor: bgColor, + foregroundColor: fgColor, + centerTitle: false, + titleSpacing: 0, + elevation: 0.5, + iconTheme: IconThemeData(color: fgColor), + actionsIconTheme: IconThemeData(color: fgColor), + ); + } } } diff --git a/lib/src/components/organisms/bottom_bar.dart b/lib/src/components/organisms/bottom_bar.dart index 7ff6537..921e0f1 100644 --- a/lib/src/components/organisms/bottom_bar.dart +++ b/lib/src/components/organisms/bottom_bar.dart @@ -1,9 +1,9 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; -/// A Container typically used with [Scaffold.bottomNavigationBar], in [showZdsBottomSheet].bottomBuilder, or as the +/// A container typically used with [Scaffold.bottomNavigationBar], in [showZdsBottomSheet].bottomBuilder, or as the /// last child of a [Column] that contains an [Expanded] to ensure [ZdsBottomBar] stays at the bottom. /// /// Typically used with a [Scaffold]: @@ -30,6 +30,18 @@ import '../../../zds_flutter.dart'; /// ensure that the ZdsBottomBar covers the entire width of the screen, and that it is not used anywhere but in the /// bottom of the screen. class ZdsBottomBar extends StatelessWidget implements PreferredSizeWidget { + /// Creates a bottom bar that can be used as a bottom application bar, or as a bottom action bar + /// + /// If [color], [shadows], and [contentPadding] are null, their [ZdsBottomBarTheme] values will be used instead. + const ZdsBottomBar({ + super.key, + this.child, + this.color, + this.shadows, + this.minHeight = kBottomBarHeight, + this.contentPadding, + }); + /// The widget that will be below this widget in the widget tree, typically a [Row]. final Widget? child; @@ -46,21 +58,9 @@ class ZdsBottomBar extends StatelessWidget implements PreferredSizeWidget { /// Defaults to the [ZdsBottomBarTheme] value. final EdgeInsets? contentPadding; - /// Creates a bottom bar that can be used as a bottom application bar, or as a bottom action bar - /// - /// If [color], [shadows], and [contentPadding] are null, their [ZdsBottomBarTheme] values will be used instead. - const ZdsBottomBar({ - super.key, - this.child, - this.color, - this.shadows, - this.minHeight = kBottomBarHeight, - this.contentPadding, - }); - @override Widget build(BuildContext context) { - final customTheme = ZdsBottomBarTheme.of(context); + final ZdsBottomBarThemeData customTheme = ZdsBottomBarTheme.of(context); return DecoratedBox( decoration: BoxDecoration( color: color ?? customTheme.backgroundColor, diff --git a/lib/src/components/organisms/bottom_tab_bar.dart b/lib/src/components/organisms/bottom_tab_bar.dart index 4581a1c..d392f97 100644 --- a/lib/src/components/organisms/bottom_tab_bar.dart +++ b/lib/src/components/organisms/bottom_tab_bar.dart @@ -1,10 +1,19 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; /// Defines a button for [ZdsBottomTabBar] or [ZdsVerticalNav]. Used in [ZdsBottomTabBar.items]. class ZdsNavItem { + /// Creates a button to be used in [ZdsBottomTabBar] + const ZdsNavItem({ + required this.label, + required this.icon, + this.semanticLabel, + this.semanticState = '', + this.id, + }); + /// used for automation purpose final String? id; @@ -23,15 +32,6 @@ class ZdsNavItem { /// /// if [ZdsNavItem] state is selected then this get appended to the [semanticLabel]. final String semanticState; - - /// Creates a button to be used in [ZdsBottomTabBar] - const ZdsNavItem({ - required this.label, - required this.icon, - this.semanticLabel, - this.semanticState = '', - this.id, - }); } /// A [ZdsBottomBar] used to switch between different views. Typically used as a [Scaffold.bottomNavigationBar] in a @@ -47,6 +47,21 @@ class ZdsNavItem { /// ) /// ``` class ZdsBottomTabBar extends StatelessWidget implements PreferredSizeWidget { + /// Creates a bottom tab navigation bar + /// + /// [items] can't be null. [currentIndex]'s value must be equal or greater than 0, and smaller than [items].length. + const ZdsBottomTabBar({ + required this.items, + super.key, + this.currentIndex = 0, + this.onTap, + this.contentPadding, + this.minHeight = kBottomBarHeight, + }) : assert( + 0 <= currentIndex && currentIndex < items.length, + 'currentIndex must not be greater than the number of items', + ); + /// The [ZdsBottomTabBar] list that will be displayed. Each item should be linked to a separate view. final List items; @@ -70,26 +85,11 @@ class ZdsBottomTabBar extends StatelessWidget implements PreferredSizeWidget { /// Defaults to [kBottomBarHeight]. final double minHeight; - /// Creates a bottom tab navigation bar - /// - /// [items] can't be null. [currentIndex]'s value must be equal or greater than 0, and smaller than [items].length. - const ZdsBottomTabBar({ - required this.items, - super.key, - this.currentIndex = 0, - this.onTap, - this.contentPadding, - this.minHeight = kBottomBarHeight, - }) : assert( - 0 <= currentIndex && currentIndex < items.length, - 'currentIndex must not be greater than the number of items', - ); - @override Widget build(BuildContext context) { - final theme = Theme.of(context).bottomNavigationBarTheme; - final zdsBottomBarTheme = ZdsBottomBarTheme.of(context); - final tabBarContentPadding = contentPadding ?? + final BottomNavigationBarThemeData theme = Theme.of(context).bottomNavigationBarTheme; + final ZdsBottomBarThemeData zdsBottomBarTheme = ZdsBottomBarTheme.of(context); + final EdgeInsets tabBarContentPadding = contentPadding ?? zdsBottomBarTheme.contentPadding.copyWith( left: 0, right: 0, @@ -103,13 +103,13 @@ class ZdsBottomTabBar extends StatelessWidget implements PreferredSizeWidget { overflow: TextOverflow.ellipsis, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - for (var i = 0; i < items.length; i++) + children: [ + for (int i = 0; i < items.length; i++) () { - final selected = i == currentIndex; + final bool selected = i == currentIndex; //keeping key empty for other apps should be replaced with proper translation once added in repo. - final finalSemanticLabel = ComponentStrings.of(context) - .get('', items[i].semanticLabel ?? items[i].label, args: ['${i + 1}', '${items.length}']); + final String finalSemanticLabel = ComponentStrings.of(context) + .get('', items[i].semanticLabel ?? items[i].label, args: ['${i + 1}', '${items.length}']); return Expanded( child: Semantics( excludeSemantics: true, @@ -147,22 +147,16 @@ class ZdsBottomTabBar extends StatelessWidget implements PreferredSizeWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IntProperty('currentIndex', currentIndex)); - properties.add(IterableProperty('items', items)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(DiagnosticsProperty('contentPadding', contentPadding)); - properties.add(DoubleProperty('minHeight', minHeight)); + properties + ..add(IntProperty('currentIndex', currentIndex)) + ..add(IterableProperty('items', items)) + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(DiagnosticsProperty('contentPadding', contentPadding)) + ..add(DoubleProperty('minHeight', minHeight)); } } class _ZdsBottomTabBarTile extends StatelessWidget { - final VoidCallback? onTap; - final Widget icon; - final String label; - final bool selected; - final String? id; - final TextStyle labelStyle; - const _ZdsBottomTabBarTile({ required this.icon, required this.label, @@ -171,10 +165,16 @@ class _ZdsBottomTabBarTile extends StatelessWidget { this.id, this.onTap, }); + final VoidCallback? onTap; + final Widget icon; + final String label; + final bool selected; + final String? id; + final TextStyle labelStyle; @override Widget build(BuildContext context) { - final effectiveTooltip = label; + final String effectiveTooltip = label; Widget result = ConstrainedBox( constraints: const BoxConstraints(minHeight: 48, minWidth: 48), child: InkResponse( @@ -216,10 +216,11 @@ class _ZdsBottomTabBarTile extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(ObjectFlagProperty.has('onTap', onTap)); - properties.add(StringProperty('label', label)); - properties.add(DiagnosticsProperty('selected', selected)); - properties.add(StringProperty('id', id)); - properties.add(DiagnosticsProperty('labelStyle', labelStyle)); + properties + ..add(ObjectFlagProperty.has('onTap', onTap)) + ..add(StringProperty('label', label)) + ..add(DiagnosticsProperty('selected', selected)) + ..add(StringProperty('id', id)) + ..add(DiagnosticsProperty('labelStyle', labelStyle)); } } diff --git a/lib/src/components/organisms/calendar.dart b/lib/src/components/organisms/calendar.dart index 5a1a5a7..d1f1743 100644 --- a/lib/src/components/organisms/calendar.dart +++ b/lib/src/components/organisms/calendar.dart @@ -2,29 +2,139 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:table_calendar/table_calendar.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/localizations/translation.dart'; +import '../../utils/theme.dart'; +import '../../utils/tools/modifiers.dart'; +import '../../utils/tools/utils.dart'; +import '../molecules/menu.dart'; enum _ZdsCalendarVariant { switchable, monthly, weekly } /// An adaptable calendar widget that can be used in a variety of ways, with selectable days and date ranges, as well /// as event markers and different formats. /// +/// Extended from [TableCalendar]. +/// /// This calendar has three variants, each called with a different constructor: /// * [ZdsCalendar], which allows to switch between a monthly and weekly format. It always has a header with the /// current month and a format switcher. /// * [ZdsCalendar.monthly], which shows a calendar with a fixed month format. /// * [ZdsCalendar.weekly], which shows a calendar with a fixed week format. /// -/// For this widget, the [selectedDay] refers to the day currently selected (with a filled circle surrounding it), -/// while [TableCalendar.focusedDay] refers to the day that is currently in focus (shown on screen). The [TableCalendar.focusedDay] has no +/// For this widget, the [selectedDay] refers to the day currently selected (i.e., with a filled circle surrounding it), +/// while [TableCalendar.focusedDay] refers to the day that is currently in focus (i.e., shown on screen). The [TableCalendar.focusedDay] has no /// special decoration and looks like any other day. The [selectedDay] may not be the [TableCalendar.focusedDay] and may not be -/// displayed on screen (the user selects a day on February and changes the month to March, making [selectedDay] a +/// displayed on screen (e.g. the user selects a day on February and changes the month to March, making [selectedDay] a /// day in February and [TableCalendar.focusedDay] a day in March). /// /// Several callback functions are available to sync other widgets with this one. These are [onDaySelected], /// [onRangeSelected], and [onPageChanged]. class ZdsCalendar extends StatefulWidget { + /// Calendar widget that allows to switch between a monthly and weekly format. As such, the calendar header will + /// always be shown. To not show the calendar header and use a monthly format, use [ZdsCalendar.monthly] instead. + const ZdsCalendar({ + required this.events, + super.key, + this.showAllButton = false, + this.onAllSelected, + this.firstDay, + this.lastDay, + this.initialSelectedDay, + this.selectedDay, + this.startingDayOfWeek, + this.initialSelectedWeek, + this.weekIcons, + this.isRangeSelectable = false, + this.isGridShown = false, + this.onDaySelected, + this.onRangeSelected, + this.onPageChanged, + this.onFormatChanged, + this.headerPadding = const EdgeInsets.fromLTRB(4, 8, 8, 8), + this.singleMarkerBuilder, + this.availableGestures = AvailableGestures.horizontalSwipe, + this.enabled = true, + this.calendarHeaderIconColor, + this.calendarHeaderTextColor, + this.calendarTextColor, + this.holidayEvents = const [], + this.allCustomLabel, + this.calendarRowHeight, + this.previousTooltip, + this.nextTooltip, + }) : _variant = _ZdsCalendarVariant.switchable, + hasHeader = true; + + /// Shows a calendar in a fixed monthly format. + const ZdsCalendar.monthly({ + required this.events, + super.key, + this.showAllButton = false, + this.onAllSelected, + this.firstDay, + this.lastDay, + this.initialSelectedDay, + this.selectedDay, + this.startingDayOfWeek, + this.initialSelectedWeek, + this.hasHeader = true, + this.weekIcons, + this.isRangeSelectable = false, + this.isGridShown = false, + this.onDaySelected, + this.onRangeSelected, + this.onPageChanged, + this.onFormatChanged, + this.headerPadding = const EdgeInsets.fromLTRB(4, 8, 8, 8), + this.singleMarkerBuilder, + this.availableGestures = AvailableGestures.horizontalSwipe, + this.enabled = true, + this.calendarHeaderIconColor, + this.calendarHeaderTextColor, + this.calendarTextColor, + this.holidayEvents = const [], + this.allCustomLabel, + this.calendarRowHeight, + this.previousTooltip, + this.nextTooltip, + }) : _variant = _ZdsCalendarVariant.monthly; + + /// Shows a calendar in a fixed weekly format. + const ZdsCalendar.weekly({ + required this.events, + super.key, + this.showAllButton = false, + this.onAllSelected, + this.firstDay, + this.lastDay, + this.initialSelectedDay, + this.selectedDay, + this.startingDayOfWeek, + this.initialSelectedWeek, + this.isRangeSelectable = false, + this.isGridShown = false, + this.weekIcons, + this.onDaySelected, + this.onRangeSelected, + this.onPageChanged, + this.onFormatChanged, + this.headerPadding = const EdgeInsets.fromLTRB(4, 8, 8, 8), + this.singleMarkerBuilder, + this.availableGestures = AvailableGestures.horizontalSwipe, + this.enabled = true, + this.calendarHeaderIconColor, + this.calendarHeaderTextColor, + this.calendarTextColor, + this.holidayEvents = const [], + this.allCustomLabel, + this.calendarRowHeight, + this.previousTooltip, + this.nextTooltip, + }) : _variant = _ZdsCalendarVariant.weekly, + hasHeader = false; + /// The earliest date that will be shown on the calendar. final DateTime? firstDay; @@ -86,6 +196,12 @@ class ZdsCalendar extends StatefulWidget { final _ZdsCalendarVariant _variant; + /// Tooltip for the previous month button + final String? previousTooltip; + + /// Tooltip for the next month button + final String? nextTooltip; + /// Padding around the header of the calendar /// /// Defaults to EdgeInsets.fromLTRB(4, 8, 8, 8) @@ -131,146 +247,60 @@ class ZdsCalendar extends StatefulWidget { /// Defaults to 'All'. final String? allCustomLabel; - /// Calendar widget that allows to switch between a monthly and weekly format. As such, the calendar header will - /// always be shown. To not show the calendar header and use a monthly format, use [ZdsCalendar.monthly] instead. - const ZdsCalendar({ - required this.events, - super.key, - this.showAllButton = false, - this.onAllSelected, - this.firstDay, - this.lastDay, - this.initialSelectedDay, - this.selectedDay, - this.startingDayOfWeek, - this.initialSelectedWeek, - this.weekIcons, - this.isRangeSelectable = false, - this.isGridShown = false, - this.onDaySelected, - this.onRangeSelected, - this.onPageChanged, - this.onFormatChanged, - this.headerPadding = const EdgeInsets.fromLTRB(4, 8, 8, 8), - this.singleMarkerBuilder, - this.availableGestures = AvailableGestures.horizontalSwipe, - this.enabled = true, - this.calendarHeaderIconColor, - this.calendarHeaderTextColor, - this.calendarTextColor, - this.holidayEvents = const [], - this.allCustomLabel, - }) : _variant = _ZdsCalendarVariant.switchable, - hasHeader = true; - - /// Shows a calendar in a fixed monthly format. - const ZdsCalendar.monthly({ - required this.events, - super.key, - this.showAllButton = false, - this.onAllSelected, - this.firstDay, - this.lastDay, - this.initialSelectedDay, - this.selectedDay, - this.startingDayOfWeek, - this.initialSelectedWeek, - this.hasHeader = true, - this.weekIcons, - this.isRangeSelectable = false, - this.isGridShown = false, - this.onDaySelected, - this.onRangeSelected, - this.onPageChanged, - this.onFormatChanged, - this.headerPadding = const EdgeInsets.fromLTRB(4, 8, 8, 8), - this.singleMarkerBuilder, - this.availableGestures = AvailableGestures.horizontalSwipe, - this.enabled = true, - this.calendarHeaderIconColor, - this.calendarHeaderTextColor, - this.calendarTextColor, - this.holidayEvents = const [], - this.allCustomLabel, - }) : _variant = _ZdsCalendarVariant.monthly; - - /// Shows a calendar in a fixed weekly format. - const ZdsCalendar.weekly({ - required this.events, - super.key, - this.showAllButton = false, - this.onAllSelected, - this.firstDay, - this.lastDay, - this.initialSelectedDay, - this.selectedDay, - this.startingDayOfWeek, - this.initialSelectedWeek, - this.isRangeSelectable = false, - this.isGridShown = false, - this.weekIcons, - this.onDaySelected, - this.onRangeSelected, - this.onPageChanged, - this.onFormatChanged, - this.headerPadding = const EdgeInsets.fromLTRB(4, 8, 8, 8), - this.singleMarkerBuilder, - this.availableGestures = AvailableGestures.horizontalSwipe, - this.enabled = true, - this.calendarHeaderIconColor, - this.calendarHeaderTextColor, - this.calendarTextColor, - this.holidayEvents = const [], - this.allCustomLabel, - }) : _variant = _ZdsCalendarVariant.weekly, - hasHeader = false; + /// an override for calendar row height + final double? calendarRowHeight; @override State createState() => _ZdsCalendarState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('firstDay', firstDay)); - properties.add(DiagnosticsProperty('lastDay', lastDay)); - properties.add(DiagnosticsProperty('initialSelectedDay', initialSelectedDay)); - properties.add(DiagnosticsProperty('selectedDay', selectedDay)); - properties.add(EnumProperty('startingDayOfWeek', startingDayOfWeek)); - properties.add(DiagnosticsProperty('initialSelectedWeek', initialSelectedWeek)); - properties.add(DiagnosticsProperty('showAllButton', showAllButton)); - properties.add(DiagnosticsProperty('isRangeSelectable', isRangeSelectable)); - properties.add(IterableProperty('events', events)); - properties.add(DiagnosticsProperty('hasHeader', hasHeader)); - properties.add(IterableProperty('weekIcons', weekIcons)); - properties.add(DiagnosticsProperty('isGridShown', isGridShown)); - properties.add(ObjectFlagProperty.has('onDaySelected', onDaySelected)); - properties.add( - ObjectFlagProperty.has( - 'onRangeSelected', - onRangeSelected, - ), - ); - properties.add(ObjectFlagProperty.has('onPageChanged', onPageChanged)); - properties.add( - ObjectFlagProperty.has( - 'onAllSelected', - onAllSelected, - ), - ); - properties.add(ObjectFlagProperty.has('onFormatChanged', onFormatChanged)); - properties.add(DiagnosticsProperty('headerPadding', headerPadding)); - properties.add( - ObjectFlagProperty.has( - 'singleMarkerBuilder', - singleMarkerBuilder, - ), - ); - properties.add(EnumProperty('availableGestures', availableGestures)); - properties.add(DiagnosticsProperty('enabled', enabled)); - properties.add(ColorProperty('calendarHeaderIconColor', calendarHeaderIconColor)); - properties.add(ColorProperty('calendarHeaderTextColor', calendarHeaderTextColor)); - properties.add(ColorProperty('calendarTextColor', calendarTextColor)); - properties.add(IterableProperty('holidayEvents', holidayEvents)); - properties.add(StringProperty('allCustomLabel', allCustomLabel)); + properties + ..add(DiagnosticsProperty('firstDay', firstDay)) + ..add(DiagnosticsProperty('lastDay', lastDay)) + ..add(DiagnosticsProperty('initialSelectedDay', initialSelectedDay)) + ..add(DiagnosticsProperty('selectedDay', selectedDay)) + ..add(EnumProperty('startingDayOfWeek', startingDayOfWeek)) + ..add(DiagnosticsProperty('initialSelectedWeek', initialSelectedWeek)) + ..add(DiagnosticsProperty('showAllButton', showAllButton)) + ..add(DiagnosticsProperty('isRangeSelectable', isRangeSelectable)) + ..add(IterableProperty('events', events)) + ..add(DiagnosticsProperty('hasHeader', hasHeader)) + ..add(IterableProperty('weekIcons', weekIcons)) + ..add(DiagnosticsProperty('isGridShown', isGridShown)) + ..add(ObjectFlagProperty.has('onDaySelected', onDaySelected)) + ..add( + ObjectFlagProperty.has( + 'onRangeSelected', + onRangeSelected, + ), + ) + ..add(ObjectFlagProperty.has('onPageChanged', onPageChanged)) + ..add( + ObjectFlagProperty.has( + 'onAllSelected', + onAllSelected, + ), + ) + ..add(ObjectFlagProperty.has('onFormatChanged', onFormatChanged)) + ..add(StringProperty('previousTooltip', previousTooltip)) + ..add(StringProperty('nextTooltip', nextTooltip)) + ..add(DiagnosticsProperty('headerPadding', headerPadding)) + ..add( + ObjectFlagProperty.has( + 'singleMarkerBuilder', + singleMarkerBuilder, + ), + ) + ..add(EnumProperty('availableGestures', availableGestures)) + ..add(DiagnosticsProperty('enabled', enabled)) + ..add(ColorProperty('calendarHeaderIconColor', calendarHeaderIconColor)) + ..add(ColorProperty('calendarHeaderTextColor', calendarHeaderTextColor)) + ..add(ColorProperty('calendarTextColor', calendarTextColor)) + ..add(IterableProperty('holidayEvents', holidayEvents)) + ..add(StringProperty('allCustomLabel', allCustomLabel)) + ..add(DoubleProperty('calendarRowHeight', calendarRowHeight)); } } @@ -311,11 +341,12 @@ class _ZdsCalendarState extends State { .copyWith(color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.w500); final StartingDayOfWeek startingDayOfWeek = widget.startingDayOfWeek ?? StartingDayOfWeek.sunday; + final zetaColors = Zeta.of(context).colors; final calendar = TableCalendar( startingDayOfWeek: startingDayOfWeek, availableGestures: widget.availableGestures, - rowHeight: calendarRowHeight, - // TODO(calendar): Determine initial and final dates + rowHeight: widget.calendarRowHeight ?? calendarRowHeight, + // TODO(CALENDAR): Determine initial and final dates firstDay: widget.firstDay ?? DateTime.fromMillisecondsSinceEpoch(0), lastDay: widget.lastDay ?? DateTime(17776), focusedDay: _focusedDay, @@ -349,7 +380,7 @@ class _ZdsCalendarState extends State { }); widget.onRangeSelected?.call(start, end, focusedDay); }, - // TODO(calendar): Figure out why this onFormatChanged function doesn't seem to be called when changing the format + // TODO(onFormatChanged): Figure out why this onFormatChanged function doesn't seem to be called when changing the format // Currently, a workaround is being used. onFormatChanged: (format) { if (_calendarFormat != format) { @@ -361,9 +392,6 @@ class _ZdsCalendarState extends State { onPageChanged: (focusedDay) { setState(() { _focusedDay = focusedDay; - if (!widget.isRangeSelectable && !widget.showAllButton) { - _selectedDay = focusedDay; - } }); widget.onPageChanged?.call(focusedDay); }, @@ -379,11 +407,9 @@ class _ZdsCalendarState extends State { padding: const EdgeInsets.only(top: 4), child: Text( text, - style: Theme.of(context).textTheme.titleSmall!.copyWith( + style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w500, - color: ZdsColors.greySwatch( - context, - )[Theme.of(context).colorScheme.brightness == Brightness.dark ? 700 : 900], + color: zetaColors.textSubtle, ), textAlign: TextAlign.center, ), @@ -397,13 +423,14 @@ class _ZdsCalendarState extends State { tableBorder: widget.isGridShown ? TableBorder( borderRadius: BorderRadius.circular(4), - horizontalInside: BorderSide(color: ZdsColors.greyCoolSwatch.shade100), - verticalInside: BorderSide(color: ZdsColors.greyCoolSwatch.shade100), - left: BorderSide(color: ZdsColors.greyCoolSwatch.shade100), - right: BorderSide(color: ZdsColors.greyCoolSwatch.shade100), + horizontalInside: BorderSide(color: zetaColors.borderSubtle), + verticalInside: BorderSide(color: zetaColors.borderSubtle), + left: BorderSide(color: zetaColors.borderSubtle), + right: BorderSide(color: zetaColors.borderSubtle), ) : const TableBorder(), - markersMaxCount: 1, // TODO(calendar): Redefine this if we want multiple dots. + markersMaxCount: 1, + // TODO(CALENDAR): Redefine this if we want multiple dots. markerSize: 5, markerMargin: EdgeInsets.only( top: widget._variant == _ZdsCalendarVariant.weekly @@ -421,28 +448,28 @@ class _ZdsCalendarState extends State { color: widget.calendarTextColor ?? Theme.of(context).colorScheme.onBackground, ), holidayDecoration: BoxDecoration( - color: ZdsColors.greyWarmSwatch[200], + color: zetaColors.warm.surface, shape: BoxShape.circle, ), - selectedTextStyle: textTheme.copyWith(color: Theme.of(context).colorScheme.onSecondary), - outsideTextStyle: textTheme.copyWith(color: ZdsColors.blueGrey), - rangeStartTextStyle: textTheme.copyWith(color: ZdsColors.white), - rangeEndTextStyle: textTheme.copyWith(color: ZdsColors.white), - rangeHighlightColor: Theme.of(context).colorScheme.secondary.withOpacity(0.1), + selectedTextStyle: textTheme.copyWith(color: zetaColors.secondary.onColor), + outsideTextStyle: textTheme.copyWith(color: zetaColors.textSubtle), + rangeStartTextStyle: textTheme.copyWith(color: zetaColors.secondary.onColor), + rangeEndTextStyle: textTheme.copyWith(color: zetaColors.secondary.onColor), + rangeHighlightColor: zetaColors.secondary.surface, rangeStartDecoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondary, + color: zetaColors.secondary, shape: BoxShape.circle, ), rangeEndDecoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondary, + color: zetaColors.secondary, shape: BoxShape.circle, ), markerDecoration: BoxDecoration( - color: ZdsColors.blueGrey, + color: zetaColors.iconSubtle, shape: BoxShape.circle, ), selectedDecoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondary, + color: zetaColors.secondary, shape: BoxShape.circle, ), todayDecoration: BoxDecoration( @@ -462,21 +489,31 @@ class _ZdsCalendarState extends State { ) .backgroundColor(Theme.of(context).colorScheme.surface); + void previousMonthTap() { + setState(() => _focusedDay = _focusedDay.startOfMonth.subtract(const Duration(days: 1))); + } + + void nextMonthTap() { + setState(() => _focusedDay = _focusedDay.endOfMonth.add(const Duration(days: 1))); + } + final calendarHeader = Container( color: Theme.of(context).colorScheme.surface, padding: widget.headerPadding, child: Material( child: Row( children: [ - IconButton( - icon: const Icon(Icons.chevron_left), - color: widget.calendarHeaderIconColor ?? Theme.of(context).colorScheme.onSurface, - splashRadius: 24, - tooltip: MaterialLocalizations.of(context).previousMonthTooltip, - onPressed: () => setState( - () => _focusedDay = _focusedDay.startOfMonth.subtract( - const Duration(days: 1), - ), + Semantics( + excludeSemantics: true, + button: true, + label: widget.previousTooltip ?? MaterialLocalizations.of(context).previousMonthTooltip, + onTap: previousMonthTap, + child: IconButton( + icon: const Icon(Icons.chevron_left), + color: widget.calendarHeaderIconColor ?? Theme.of(context).colorScheme.onSurface, + splashRadius: 24, + tooltip: MaterialLocalizations.of(context).previousMonthTooltip, + onPressed: previousMonthTap, ), ), ZdsPopupMenu( @@ -505,7 +542,7 @@ class _ZdsCalendarState extends State { button: true, child: Text( _focusedDay.format('MMMM yyyy', languageCode), - style: Theme.of(context).textTheme.titleSmall?.copyWith( + style: Theme.of(context).textTheme.headlineMedium!.copyWith( color: widget.calendarHeaderTextColor ?? Theme.of(context).colorScheme.onBackground, ), ), @@ -514,12 +551,18 @@ class _ZdsCalendarState extends State { ), ), ), - IconButton( - icon: const Icon(Icons.chevron_right), - color: widget.calendarHeaderIconColor ?? Theme.of(context).colorScheme.onSurface, - splashRadius: 24, - tooltip: MaterialLocalizations.of(context).nextMonthTooltip, - onPressed: () => setState(() => _focusedDay = _focusedDay.endOfMonth.add(const Duration(days: 1))), + Semantics( + excludeSemantics: true, + button: true, + label: widget.nextTooltip ?? MaterialLocalizations.of(context).nextMonthTooltip, + onTap: nextMonthTap, + child: IconButton( + icon: const Icon(Icons.chevron_right), + color: widget.calendarHeaderIconColor ?? Theme.of(context).colorScheme.onSurface, + splashRadius: 24, + tooltip: MaterialLocalizations.of(context).nextMonthTooltip, + onPressed: nextMonthTap, + ), ), const Spacer(), if (widget._variant == _ZdsCalendarVariant.switchable) @@ -597,9 +640,7 @@ class _ZdsCalendarState extends State { widget.allCustomLabel ?? ComponentStrings.of(context).get('ALL', 'All'), style: Theme.of(context).textTheme.titleSmall!.copyWith( fontWeight: FontWeight.w500, - color: ZdsColors.greySwatch( - context, - )[Theme.of(context).colorScheme.brightness == Brightness.dark ? 700 : 900], + color: zetaColors.textSubtle, ), ), ), @@ -629,9 +670,7 @@ class _ZdsCalendarState extends State { _selectedDay == null ? Theme.of(context).colorScheme.secondary : Theme.of(context).colorScheme.surface, border: Border.fromBorderSide( BorderSide( - color: _selectedDay == null - ? Theme.of(context).colorScheme.secondary - : ZdsColors.greySwatch(context)[400]!, + color: _selectedDay == null ? Theme.of(context).colorScheme.secondary : zetaColors.borderSubtle, width: 1.5, ), ), @@ -680,7 +719,7 @@ class _ZdsCalendarState extends State { final bool isFirstDayOfWeek = widget.weekIcons!.every((weekIcon) => weekIcon.firstDayOfWeek != null); if (isWeekNumber || isFirstDayOfWeek) { - final List items = isWeekNumber ? weekNumbers : weekStartDays; + final items = isWeekNumber ? weekNumbers : weekStartDays; return Column( children: [ const SizedBox(height: calendarDaysOfWeekHeight), @@ -698,9 +737,9 @@ class _ZdsCalendarState extends State { ); } } else { - if (index is DateTime && - widget.weekIcons! - .any((weeks) => weeks.firstDayOfWeek?.isSameDay(index) ?? false)) { + if (widget.weekIcons!.any( + (weeks) => weeks.firstDayOfWeek?.isSameDay(index as DateTime) ?? false, + )) { return widget.weekIcons! .firstWhere((weeks) => weeks.firstDayOfWeek == index); } @@ -711,10 +750,7 @@ class _ZdsCalendarState extends State { label: week.semanticLabel, child: IconTheme( data: IconThemeData( - color: ZdsColors.greySwatch(context)[ - Theme.of(context).colorScheme.brightness == Brightness.dark - ? 700 - : 900], + color: zetaColors.iconDefault, size: context.isSmallScreen() ? 18 : 24, ), child: week.child, @@ -768,8 +804,9 @@ class _ZdsCalendarState extends State { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('startOfweek', startOfweek)); - properties.add(DiagnosticsProperty('endOfweek', endOfweek)); + properties + ..add(DiagnosticsProperty('startOfweek', startOfweek)) + ..add(DiagnosticsProperty('endOfweek', endOfweek)); } } @@ -778,20 +815,32 @@ DateTime getDate(DateTime d) => DateTime(d.year, d.month, d.day); /// Calendar Event model. class CalendarEvent { + /// Constructs a [CalendarEvent]. + const CalendarEvent({required this.id, required this.date}); + /// Id of the event. final String id; /// Date / Time of the event. final DateTime date; - - /// Constructs a [CalendarEvent]. - const CalendarEvent({required this.id, required this.date}); } /// Model for weeks that should have leading icons. /// /// Should use either both `year` and `weekNumber` or `firstDayOfWeek`. class WeekIcon { + /// Constructs a [WeekIcon]. + WeekIcon({ + required this.child, + this.year, + this.weekNumber, + this.firstDayOfWeek, + this.semanticLabel, + }) : assert( + year != null && weekNumber != null || firstDayOfWeek != null, + 'Should use either both year and weekNumber or firstDayOfWeek', + ); + /// Year of week. final int? year; @@ -810,16 +859,4 @@ class WeekIcon { /// Semantic label for icon. final String? semanticLabel; - - /// Constructs a [WeekIcon]. - WeekIcon({ - required this.child, - this.year, - this.weekNumber, - this.firstDayOfWeek, - this.semanticLabel, - }) : assert( - year != null && weekNumber != null || firstDayOfWeek != null, - 'Should use either both year and weekNumber or firstDayOfWeek', - ); } diff --git a/lib/src/components/organisms/date_range.dart b/lib/src/components/organisms/date_range.dart index 0ca99a8..2db3c22 100644 --- a/lib/src/components/organisms/date_range.dart +++ b/lib/src/components/organisms/date_range.dart @@ -2,7 +2,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import '../../../zds_flutter.dart'; +import '../../../../zds_flutter.dart'; + +/// A date range selector that also allows to quickly change the range selected by jumping to the next or +/// previous set of dates. +@Deprecated('Use ZdsDateRange instead') +typedef DateRange = ZdsDateRange; /// A date range selector that also allows to quickly change the range selected by jumping to the next or /// previous set of dates. @@ -35,8 +40,31 @@ import '../../../zds_flutter.dart'; /// /// * [ZdsDateRangePickerTile], which allows to select a date range's start and end time separately. /// * [ZdsDateTimePicker], a widget that allow to select a single date, a single time, or both. -class DateRange extends StatefulWidget { - static const _kYearsFromNow = 20; +class ZdsDateRange extends StatefulWidget { + /// Creates a date range selector. + const ZdsDateRange({ + super.key, + this.firstDate, + this.lastDate, + this.initialDateRange, + this.onChange, + this.actions, + this.emptyLabel = '', + this.textStyle, + this.clearButtonString, + this.applyButtonString, + this.isSelectable = true, + this.dateRangeSeparator = '-', + this.nextTooltip, + this.previousTooltip, + this.isWeekMode = false, + this.startDayOfWeek = 0, + this.dateFormat, + }) : assert( + !isWeekMode || (startDayOfWeek >= 0 && startDayOfWeek <= 6), + 'startingDayOfWeek must be an int between 0 and 6', + ); + static const int _kYearsFromNow = 20; /// The earliest date that can be chosen for the range. /// @@ -112,32 +140,9 @@ class DateRange extends StatefulWidget { /// to change date format of date range final String? dateFormat; - /// Creates a date range selector. - const DateRange({ - super.key, - this.firstDate, - this.lastDate, - this.initialDateRange, - this.onChange, - this.actions, - this.emptyLabel = '', - this.textStyle, - this.clearButtonString, - this.applyButtonString, - this.isSelectable = true, - this.dateRangeSeparator = '-', - this.nextTooltip, - this.previousTooltip, - this.isWeekMode = false, - this.startDayOfWeek = 0, - this.dateFormat, - }) : assert( - !isWeekMode || (startDayOfWeek >= 0 && startDayOfWeek <= 6), - 'startingDayOfWeek must be an int between 0 and 6', - ); - @override - DateRangeState createState() => DateRangeState(); + ZdsDateRangeState createState() => ZdsDateRangeState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -155,18 +160,18 @@ class DateRange extends StatefulWidget { ..add(StringProperty('previousTooltip', previousTooltip)) ..add(StringProperty('nextTooltip', nextTooltip)) ..add(DiagnosticsProperty('isWeekMode', isWeekMode)) - ..add(IntProperty('startDayOfWeek', startDayOfWeek)); - properties.add(StringProperty('dateFormat', dateFormat)); + ..add(IntProperty('startDayOfWeek', startDayOfWeek)) + ..add(StringProperty('dateFormat', dateFormat)); } } -/// State for [DateRange]. -class DateRangeState extends State { +/// State for [ZdsDateRange]. +class ZdsDateRangeState extends State { DateTimeRange? _selectedDateRange; Duration? _diff; @override - void didUpdateWidget(DateRange oldWidget) { + void didUpdateWidget(ZdsDateRange oldWidget) { super.didUpdateWidget(oldWidget); if (widget.initialDateRange != null && widget.initialDateRange != oldWidget.initialDateRange) { @@ -190,18 +195,20 @@ class DateRangeState extends State { } Future _showDateSelector(BuildContext context) async { - final range = await showZdsDateRangePicker( + final DateTimeRange? range = await showZdsDateRangePicker( context: context, actions: widget.actions, initialDateRange: _selectedDateRange, useRootNavigator: false, firstDate: widget.firstDate ?? DateTime(1999), - lastDate: widget.lastDate ?? DateTime(DateTime.now().year + DateRange._kYearsFromNow), + lastDate: widget.lastDate ?? DateTime(DateTime.now().year + ZdsDateRange._kYearsFromNow), initialEntryMode: DatePickerEntryMode.calendarOnly, clearButtonString: widget.clearButtonString, applyButtonString: widget.applyButtonString, isWeekMode: widget.isWeekMode, startingDayOfWeek: widget.startDayOfWeek, + shortDateFormat: widget.dateFormat, + shortMonthDayFormat: widget.dateFormat, ); if (mounted) { setState(() { @@ -224,7 +231,7 @@ class DateRangeState extends State { setState(() { // If current whole month is selected then select next whole month if (_selectedDateRange!.isWholeMonth) { - final start = DateTime( + final DateTime start = DateTime( _selectedDateRange!.start.year, _selectedDateRange!.start.month + 1, _selectedDateRange!.start.day, @@ -249,7 +256,7 @@ class DateRangeState extends State { setState(() { // If current whole month is selected then select previous whole month if (_selectedDateRange!.isWholeMonth) { - final start = DateTime( + final DateTime start = DateTime( _selectedDateRange!.start.year, _selectedDateRange!.start.month - 1, _selectedDateRange!.start.day, @@ -299,23 +306,34 @@ class DateRangeState extends State { @override Widget build(BuildContext context) { - final textStyle = widget.textStyle ?? Theme.of(context).primaryTextTheme.bodyLarge!; - final text = DefaultTextStyle( - style: textStyle, - maxLines: 1, - overflow: TextOverflow.ellipsis, - child: Text( - _selectedDateRange == null ? widget.emptyLabel : _formatRange(context, dateFormat: widget.dateFormat), - ), + final isBeforeFirstDate = _isBeforeFirstDate(); + final isAfterLastDate = _isAfterLastDate(); + + final text = Text( + _selectedDateRange == null ? widget.emptyLabel : _formatRange(context, dateFormat: widget.dateFormat), + style: widget.textStyle, ); + return Row( children: [ - IconButton( - padding: EdgeInsets.zero, - onPressed: _isBeforeFirstDate() ? null : _prevDateRange, - tooltip: widget.previousTooltip, - splashRadius: 24, - icon: Icon(ZdsIcons.chevron_left, color: textStyle.color!.withOpacity(_isBeforeFirstDate() ? 0.5 : 1)), + Semantics( + excludeSemantics: true, + button: true, + label: widget.previousTooltip, + onTap: isBeforeFirstDate ? null : _prevDateRange, + child: IconButton( + padding: EdgeInsets.zero, + onPressed: isBeforeFirstDate ? null : _prevDateRange, + tooltip: widget.previousTooltip, + splashRadius: 24, + icon: Opacity( + opacity: isBeforeFirstDate ? 0.5 : 1, + child: Icon( + ZdsIcons.chevron_left, + color: widget.textStyle?.color, + ), + ), + ), ), if (!widget.isSelectable) text, if (widget.isSelectable) @@ -324,12 +342,24 @@ class DateRangeState extends State { onTap: () async => _showDateSelector(context), child: text.paddingInsets(const EdgeInsets.symmetric(vertical: 8)), ), - IconButton( - padding: EdgeInsets.zero, - onPressed: _isAfterLastDate() ? null : _nextDateRange, - splashRadius: 24, - tooltip: widget.nextTooltip, - icon: Icon(ZdsIcons.chevron_right, color: textStyle.color!.withOpacity(_isAfterLastDate() ? 0.5 : 1)), + Semantics( + excludeSemantics: true, + button: true, + label: widget.nextTooltip, + onTap: isAfterLastDate ? null : _nextDateRange, + child: IconButton( + padding: EdgeInsets.zero, + onPressed: isAfterLastDate ? null : _nextDateRange, + splashRadius: 24, + tooltip: widget.nextTooltip, + icon: Opacity( + opacity: isAfterLastDate ? 0.5 : 1, + child: Icon( + ZdsIcons.chevron_right, + color: widget.textStyle?.color, + ), + ), + ), ), ], ); @@ -338,11 +368,11 @@ class DateRangeState extends State { /// Returns a locale-appropriate string to describe the start of a date range. String _formatRange(BuildContext context, {String? dateFormat}) { if (_selectedDateRange == null) return ''; - final localizations = MaterialLocalizations.of(context); + final MaterialLocalizations localizations = MaterialLocalizations.of(context); if (_selectedDateRange!.isWholeMonth) { return localizations.formatMonthYear(_selectedDateRange!.start); } - final startDateFormatted = dateFormat != null + final String startDateFormatted = dateFormat != null ? DateFormat(dateFormat).format(_selectedDateRange!.start) : _formatStartDate( localizations, @@ -350,7 +380,7 @@ class DateRangeState extends State { _selectedDateRange?.end, ); - final endDateFormatted = dateFormat != null + final String endDateFormatted = dateFormat != null ? DateFormat(dateFormat).format(_selectedDateRange!.end) : _formatEndDate( localizations, diff --git a/lib/src/components/organisms/date_range_picker_tile.dart b/lib/src/components/organisms/date_range_picker_tile.dart index dc044c7..b1b7d44 100644 --- a/lib/src/components/organisms/date_range_picker_tile.dart +++ b/lib/src/components/organisms/date_range_picker_tile.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import '../../../zds_flutter.dart'; +import 'fiscal_date_picker.dart'; const double _screenColumnBreakpoint = 240; const double _padding = 20; @@ -16,15 +17,20 @@ const double _fontLineHeight = 26; /// See also: /// * [DateTimeRange] class ZdsDateTimeRange { + /// Constructor for [ZdsDateTimeRange]. + const ZdsDateTimeRange({this.start, this.end}); + + /// Constructs a [ZdsDateTimeRange] from a [DateTimeRange]. + ZdsDateTimeRange.fromDateTimeRange(DateTimeRange dateTimeRange) + : start = dateTimeRange.start, + end = dateTimeRange.end; + /// The start of the range of dates. final DateTime? start; /// The end of the range of dates. final DateTime? end; - /// Constructor for [ZdsDateTimeRange]. - const ZdsDateTimeRange({this.start, this.end}); - /// Creates a new [ZdsDateTimeRange] from this one by updating individual properties. ZdsDateTimeRange copyWith({DateTime? start, DateTime? end}) { return ZdsDateTimeRange(start: start ?? this.start, end: end ?? this.end); @@ -36,11 +42,6 @@ class ZdsDateTimeRange { /// Checks if either start or end is not set. bool get isIncomplete => start == null || end == null; - /// Constructs a [ZdsDateTimeRange] from a [DateTimeRange]. - ZdsDateTimeRange.fromDateTimeRange(DateTimeRange dateTimeRange) - : start = dateTimeRange.start, - end = dateTimeRange.end; - /// Constructs a [DateTimeRange] from an instance of [ZdsDateTimeRange] only if [isValid]. DateTimeRange? get toDateTimeRange { if (isValid) return DateTimeRange(start: start!, end: end!); @@ -73,6 +74,9 @@ class ZdsDateRangePickerTileForm extends FormField { String format = 'dd/MM/yyyy', AutovalidateMode autovalidateMode = AutovalidateMode.onUserInteraction, void Function(ZdsDateTimeRange)? onSaved, + int? startDayOfWeek, + String? okClickText, + String? cancelClickText, super.key, }) : super( validator: (ZdsDateTimeRange? d) { @@ -82,39 +86,47 @@ class ZdsDateRangePickerTileForm extends FormField { }, initialValue: initialValue, autovalidateMode: autovalidateMode, - onSaved: (d) { + onSaved: (ZdsDateTimeRange? d) { if (d != null && onSaved != null) onSaved(d); }, builder: (FormFieldState state) { return Builder( - builder: (context) { + builder: (BuildContext context) { return ZdsCard( padding: const EdgeInsets.fromLTRB(16, 8, 16, 18), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Row( - children: [ + children: [ Expanded( child: LayoutBuilder( - builder: (context, constraints) { + builder: ( + BuildContext context, + BoxConstraints constraints, + ) { final double scale = MediaQuery.of(context).textScaleFactor; final double width = _calculateWidth(constraints, scale); final bool isColumn = constraints.maxWidth <= _screenColumnBreakpoint * scale; - final List fields = [ + final List fields = [ _DateField( date: state.value?.start ?? initialValue.start, format: format, initialSelectableDate: earliestSelectableDate, finalSelectableDate: latestSelectableDate, helpText: initialHelpText, - updateDate: (newValue) { - state.didChange((state.value ?? initialValue).copyWith(start: newValue)); + updateDate: (DateTime? newValue) { + state.didChange( + (state.value ?? initialValue).copyWith(start: newValue), + ); }, - validator: (value) => state.hasError ? '' : null, + validator: (DateTime? value) => state.hasError ? '' : null, isInitialDate: true, width: width, scale: scale, + startDayOfWeek: startDayOfWeek, + okClickText: okClickText, + cancelClickText: cancelClickText, ), SizedBox( width: isColumn ? 0 : (constraints.maxWidth - (width * 2)) / 2, @@ -125,13 +137,18 @@ class ZdsDateRangePickerTileForm extends FormField { format: format, initialSelectableDate: earliestSelectableDate, finalSelectableDate: latestSelectableDate, - validator: (value) => state.hasError ? '' : null, + validator: (DateTime? value) => state.hasError ? '' : null, helpText: finalHelpText, - updateDate: (newValue) { - state.didChange((state.value ?? initialValue).copyWith(end: newValue)); + updateDate: (DateTime? newValue) { + state.didChange( + (state.value ?? initialValue).copyWith(end: newValue), + ); }, width: width, scale: scale, + startDayOfWeek: startDayOfWeek, + okClickText: okClickText, + cancelClickText: cancelClickText, ), ]; DateTime.now().copyWith(); @@ -149,10 +166,9 @@ class ZdsDateRangePickerTileForm extends FormField { if (state.hasError) Text( state.errorText ?? '', - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith(color: Theme.of(context).colorScheme.error), + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.error, + ), ).paddingOnly(top: 4), ], ), @@ -175,6 +191,34 @@ class ZdsDateRangePickerTileForm extends FormField { /// * [ZdsDateTimePicker], which allows to select a day and hour together or separately /// * [showDatePicker] to show a date picker directly class ZdsDateRangePickerTile extends StatefulWidget { + /// A DateRangePicker that allows to pick the "From" and "To" dates separately. + /// + /// If both are set, [earliestSelectableDate] must be on or before [latestSelectableDate]. + ZdsDateRangePickerTile({ + super.key, + this.initialDate, + this.finalDate, + this.onInitialDateChanged, + this.onFinalDateChanged, + this.earliestSelectableDate, + this.latestSelectableDate, + this.initialDateController, + this.finalDateController, + this.format = 'dd/MM/yyyy', + this.initialHelpText, + this.finalHelpText, + this.errorMessage = '', + this.formKey, + this.startDayOfWeek, + this.okClickText, + this.cancelClickText, + }) : assert( + (earliestSelectableDate != null && latestSelectableDate != null) + ? earliestSelectableDate.isBefore(latestSelectableDate) + : earliestSelectableDate == null, + 'Earliest selectable date must be before latest selectable date', + ); + /// The DateTime selected in the "From" field. Set this if you want pre-initialized dates. /// /// If no date is selected, the field will be blank. @@ -226,49 +270,68 @@ class ZdsDateRangePickerTile extends StatefulWidget { /// The key attached to the form within the picker that can be used to check the validation of the inputs. final GlobalKey? formKey; - /// A DateRangePicker that allows to pick the "From" and "To" dates separately. - /// - /// If both are set, [earliestSelectableDate] must be on or before [latestSelectableDate]. - ZdsDateRangePickerTile({ - super.key, - this.initialDate, - this.finalDate, - this.onInitialDateChanged, - this.onFinalDateChanged, - this.earliestSelectableDate, - this.latestSelectableDate, - this.initialDateController, - this.finalDateController, - this.format = 'dd/MM/yyyy', - this.initialHelpText, - this.finalHelpText, - this.errorMessage = '', - this.formKey, - }) : assert( - (earliestSelectableDate != null && latestSelectableDate != null) - ? earliestSelectableDate.isBefore(latestSelectableDate) - : earliestSelectableDate == null, - 'Earliest selectable date must be before latest selectable date', - ); + /// Starting day of week 1, 2, 3, Sunday, Monday, Tuesday respectively. + final int? startDayOfWeek; + + /// The text displayed on the ok button. + final String? okClickText; + + /// The text displayed on the cancel button. + final String? cancelClickText; @override State createState() => _ZdsDateRangePickerTileState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('initialDate', initialDate)); - properties.add(DiagnosticsProperty('finalDate', finalDate)); - properties.add(StringProperty('initialHelpText', initialHelpText)); - properties.add(StringProperty('finalHelpText', finalHelpText)); - properties.add(ObjectFlagProperty.has('onInitialDateChanged', onInitialDateChanged)); - properties.add(ObjectFlagProperty.has('onFinalDateChanged', onFinalDateChanged)); - properties.add(DiagnosticsProperty('earliestSelectableDate', earliestSelectableDate)); - properties.add(DiagnosticsProperty('latestSelectableDate', latestSelectableDate)); - properties.add(DiagnosticsProperty?>('initialDateController', initialDateController)); - properties.add(DiagnosticsProperty?>('finalDateController', finalDateController)); - properties.add(StringProperty('format', format)); - properties.add(StringProperty('errorMessage', errorMessage)); - properties.add(DiagnosticsProperty?>('formKey', formKey)); + properties + ..add(DiagnosticsProperty('initialDate', initialDate)) + ..add(DiagnosticsProperty('finalDate', finalDate)) + ..add(StringProperty('initialHelpText', initialHelpText)) + ..add(StringProperty('finalHelpText', finalHelpText)) + ..add( + ObjectFlagProperty.has( + 'onInitialDateChanged', + onInitialDateChanged, + ), + ) + ..add( + ObjectFlagProperty.has( + 'onFinalDateChanged', + onFinalDateChanged, + ), + ) + ..add( + DiagnosticsProperty( + 'earliestSelectableDate', + earliestSelectableDate, + ), + ) + ..add( + DiagnosticsProperty( + 'latestSelectableDate', + latestSelectableDate, + ), + ) + ..add( + DiagnosticsProperty?>( + 'initialDateController', + initialDateController, + ), + ) + ..add( + DiagnosticsProperty?>( + 'finalDateController', + finalDateController, + ), + ) + ..add(StringProperty('format', format)) + ..add(StringProperty('errorMessage', errorMessage)) + ..add(DiagnosticsProperty?>('formKey', formKey)) + ..add(IntProperty('startDayOfWeek', startDayOfWeek)) + ..add(StringProperty('okClickText', okClickText)) + ..add(StringProperty('cancelClickText', cancelClickText)); } } @@ -292,17 +355,16 @@ class _ZdsDateRangePickerTileState extends State { @override void initState() { super.initState(); - initialDate = - widget.initialDate ?? (widget.initialDateController != null ? widget.initialDateController!.value : null); - finalDate = widget.finalDate ?? (widget.finalDateController != null ? widget.finalDateController!.value : null); + initialDate = widget.initialDate ?? widget.initialDateController?.value; + finalDate = widget.finalDate ?? widget.finalDateController?.value; - widget.initialDateController?.updateListener = (value) { + widget.initialDateController?.updateListener = (DateTime? value) { setState(() { initialDate = value; }); widget.initialDateController?.notifyListeners(value); }; - widget.finalDateController?.updateListener = (value) { + widget.finalDateController?.updateListener = (DateTime? value) { setState(() { finalDate = value; }); @@ -318,19 +380,19 @@ class _ZdsDateRangePickerTileState extends State { padding: const EdgeInsets.fromLTRB(16, 8, 16, 18), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ Row( - children: [ + children: [ Expanded( child: Form( key: formKey, autovalidateMode: AutovalidateMode.onUserInteraction, child: LayoutBuilder( - builder: (context, constraints) { + builder: (BuildContext context, BoxConstraints constraints) { final double scale = MediaQuery.of(context).textScaleFactor; final double width = _calculateWidth(constraints, scale); final bool isColumn = constraints.maxWidth <= _screenColumnBreakpoint * scale; - final List fields = [ + final List fields = [ _DateField( date: initialDate, format: widget.format, @@ -338,11 +400,11 @@ class _ZdsDateRangePickerTileState extends State { initialSelectableDate: widget.earliestSelectableDate, finalSelectableDate: widget.latestSelectableDate, helpText: widget.initialHelpText, - updateDate: (newValue) { + updateDate: (DateTime? newValue) { setState(() => initialDate = newValue); widget.initialDateController?.notifyListeners(newValue); }, - validator: (value) { + validator: (DateTime? value) { if (value != null && (finalDate != null && value.isAfter(finalDate!))) { return widget.errorMessage; } @@ -351,6 +413,9 @@ class _ZdsDateRangePickerTileState extends State { isInitialDate: true, width: width, scale: scale, + startDayOfWeek: widget.startDayOfWeek, + okClickText: widget.okClickText, + cancelClickText: widget.cancelClickText, ), SizedBox( width: isColumn ? 0 : (constraints.maxWidth - (width * 2)) / 2, @@ -363,11 +428,11 @@ class _ZdsDateRangePickerTileState extends State { initialSelectableDate: widget.earliestSelectableDate, finalSelectableDate: widget.latestSelectableDate, helpText: widget.finalHelpText, - updateDate: (newValue) { + updateDate: (DateTime? newValue) { setState(() => finalDate = newValue); widget.finalDateController?.notifyListeners(newValue); }, - validator: (value) { + validator: (DateTime? value) { if (value != null && (initialDate != null && value.isBefore(initialDate!))) { return widget.errorMessage; } @@ -375,6 +440,9 @@ class _ZdsDateRangePickerTileState extends State { }, width: width, scale: scale, + startDayOfWeek: widget.startDayOfWeek, + okClickText: widget.okClickText, + cancelClickText: widget.cancelClickText, ), ]; @@ -406,25 +474,14 @@ class _ZdsDateRangePickerTileState extends State { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('initialDate', initialDate)); - properties.add(DiagnosticsProperty('finalDate', finalDate)); - properties.add(DiagnosticsProperty>('formKey', formKey)); + properties + ..add(DiagnosticsProperty('initialDate', initialDate)) + ..add(DiagnosticsProperty('finalDate', finalDate)) + ..add(DiagnosticsProperty>('formKey', formKey)); } } class _DateField extends StatelessWidget { - final DateTime? date; - final DateTime? initialSelectableDate; - final DateTime? finalSelectableDate; - final bool isInitialDate; - final void Function(DateTime?)? onDateChanged; - final void Function(DateTime?) updateDate; - final String format; - final String? helpText; - final double width; - final double scale; - final String? Function(DateTime?)? validator; - const _DateField({ required this.updateDate, required this.date, @@ -437,107 +494,167 @@ class _DateField extends StatelessWidget { this.helpText, this.onDateChanged, this.isInitialDate = false, + this.okClickText, + this.cancelClickText, + this.startDayOfWeek, }); + final DateTime? date; + final DateTime? initialSelectableDate; + final DateTime? finalSelectableDate; + final bool isInitialDate; + final void Function(DateTime?)? onDateChanged; + final void Function(DateTime?) updateDate; + final String format; + final String? helpText; + final double width; + final double scale; + final String? Function(DateTime?)? validator; + + /// Starting day of week 1, 2, 3, Sunday, Monday, Tuesday respectively. + final int? startDayOfWeek; + + /// The text displayed on the ok button. + final String? okClickText; + + /// The text displayed on the cancel button. + final String? cancelClickText; @override Widget build(BuildContext context) { return FormField( validator: validator, autovalidateMode: AutovalidateMode.onUserInteraction, - builder: (state) => Container( - width: width, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: state.hasError ? Theme.of(context).colorScheme.error : ZdsColors.lightGrey, + builder: (FormFieldState state) { + final zetaColors = Zeta.of(context).colors; + return Container( + width: width, + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: state.hasError ? Theme.of(context).colorScheme.error : zetaColors.borderSubtle, + ), ), ), - ), - child: MergeSemantics( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - isInitialDate - ? ComponentStrings.of(context).get('FROM', 'From') - : ComponentStrings.of(context).get('TO', 'To'), - style: Theme.of(context).textTheme.bodySmall?.copyWith(color: ZdsColors.greySwatch(context)[1000]), - ).paddingOnly(left: 2), - InkWell( - onTap: () async { - final DateTime initialPickerDate; - if (date != null) { - initialPickerDate = date!; - } else if (initialSelectableDate != null) { - if (initialSelectableDate!.isAfter(DateTime.now())) { - initialPickerDate = initialSelectableDate!; + child: MergeSemantics( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + isInitialDate + ? ComponentStrings.of(context).get('FROM', 'From') + : ComponentStrings.of(context).get('TO', 'To'), + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: zetaColors.textSubtle), + ).paddingOnly(left: 2), + InkWell( + onTap: () async { + final DateTime initialPickerDate; + if (date != null) { + initialPickerDate = date!; + } else if (initialSelectableDate != null) { + if (initialSelectableDate!.isAfter(DateTime.now())) { + initialPickerDate = initialSelectableDate!; + } else { + initialPickerDate = DateTime.now(); + } } else { initialPickerDate = DateTime.now(); } - } else { - initialPickerDate = DateTime.now(); - } - final DateTime? selectedDate = await showDatePicker( - context: context, - initialDate: initialPickerDate, - firstDate: initialSelectableDate ?? DateTime.now().subtract(const Duration(days: 365 * 10)), - lastDate: finalSelectableDate ?? DateTime.now().add(const Duration(days: 365 * 10)), - initialEntryMode: DatePickerEntryMode.calendarOnly, - helpText: helpText, - builder: (context, child) { - return Theme( - data: Theme.of(context).zdsDateTimePickerTheme, - child: child!, - ); - }, - ); - state.didChange(selectedDate); - if (selectedDate != null) updateDate(selectedDate); - if (onDateChanged != null) onDateChanged?.call(selectedDate); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - height: _fontLineHeight * scale, - child: date != null - ? Text( - date!.format(format), - style: Theme.of(context).textTheme.bodyLarge?.copyWith( - height: - (_fontLineHeight / Theme.of(context).textTheme.bodyLarge!.fontSize!) / scale, - ), - ) - : null, - ), - Icon( - ZdsIcons.calendar, - color: ZdsColors.greySwatch(context)[800], - size: 22, - ), - ], + final DateTime? selectedDate = await showZdsFiscalDatePicker( + format: format, + context: context, + initialDate: initialPickerDate, + firstDate: initialSelectableDate ?? DateTime.now().subtract(const Duration(days: 365 * 10)), + lastDate: finalSelectableDate ?? DateTime.now().add(const Duration(days: 365 * 10)), + titleText: helpText ?? 'Select Date', + cancelText: cancelClickText ?? ComponentStrings.of(context).get('CANCEL', 'Cancel'), + okText: okClickText ?? ComponentStrings.of(context).get('OK', 'OK'), + startDayOfWeek: startDayOfWeek ?? 1, + builder: (BuildContext context, Widget? child) { + return Theme( + data: Theme.of(context).zdsDateTimePickerTheme, + child: child!, + ); + }, + ); + state.didChange(selectedDate); + if (selectedDate != null) updateDate(selectedDate); + if (onDateChanged != null) { + onDateChanged?.call(selectedDate); + } + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + height: _fontLineHeight * scale, + child: date != null + ? Text( + date!.format(format), + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + height: + (_fontLineHeight / Theme.of(context).textTheme.bodyLarge!.fontSize!) / scale, + ), + ) + : null, + ), + Icon( + ZdsIcons.calendar, + color: zetaColors.iconSubtle, + size: 22, + ), + ], + ), ), - ), - ], + ], + ), ), - ), - ), + ); + }, ); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('date', date)); - properties.add(DiagnosticsProperty('initialSelectableDate', initialSelectableDate)); - properties.add(DiagnosticsProperty('finalSelectableDate', finalSelectableDate)); - properties.add(DiagnosticsProperty('isInitialDate', isInitialDate)); - properties.add(ObjectFlagProperty.has('onDateChanged', onDateChanged)); - properties.add(ObjectFlagProperty.has('updateDate', updateDate)); - properties.add(StringProperty('format', format)); - properties.add(StringProperty('helpText', helpText)); - properties.add(DoubleProperty('width', width)); - properties.add(DoubleProperty('scale', scale)); - properties.add(ObjectFlagProperty.has('validator', validator)); + properties + ..add(DiagnosticsProperty('date', date)) + ..add( + DiagnosticsProperty( + 'initialSelectableDate', + initialSelectableDate, + ), + ) + ..add( + DiagnosticsProperty( + 'finalSelectableDate', + finalSelectableDate, + ), + ) + ..add(DiagnosticsProperty('isInitialDate', isInitialDate)) + ..add( + ObjectFlagProperty.has( + 'onDateChanged', + onDateChanged, + ), + ) + ..add( + ObjectFlagProperty.has( + 'updateDate', + updateDate, + ), + ) + ..add(StringProperty('format', format)) + ..add(StringProperty('helpText', helpText)) + ..add(DoubleProperty('width', width)) + ..add(DoubleProperty('scale', scale)) + ..add( + ObjectFlagProperty.has( + 'validator', + validator, + ), + ) + ..add(IntProperty('startDayOfWeek', startDayOfWeek)) + ..add(StringProperty('okClickText', okClickText)) + ..add(StringProperty('cancelClickText', cancelClickText)); } } diff --git a/lib/src/components/organisms/day_picker.dart b/lib/src/components/organisms/day_picker.dart index 0f452db..8c5a78b 100644 --- a/lib/src/components/organisms/day_picker.dart +++ b/lib/src/components/organisms/day_picker.dart @@ -1,11 +1,25 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/localizations/translation.dart'; +import '../../utils/tools/modifiers.dart'; +import '../../utils/tools/utils.dart'; +import '../atoms/button.dart'; +import '../atoms/card.dart'; +import '../atoms/selection_pills.dart'; /// Model for days used in [ZdsDayPicker]. class DayDetails { + /// Constructs a [DayDetails]. + DayDetails({ + required this.date, + required this.dayText, + required this.isDisabled, + this.isChecked = false, + }); + /// Index for the day. final DateTime date; @@ -17,18 +31,27 @@ class DayDetails { /// Selected or unselected. bool isChecked; - - /// Constructs a [DayDetails]. - DayDetails({ - required this.date, - required this.dayText, - required this.isDisabled, - this.isChecked = false, - }); } /// A widget that allow to select days. class ZdsDayPicker extends StatefulWidget { + /// Constructs a [ZdsDayPicker]. + const ZdsDayPicker({ + required this.startingWeekDate, + this.initialSelectedDates, + this.header, + this.allText, + this.disableDaysList = const [], + this.onDaySelected, + this.allowMultiSelect = false, + this.showInCard = true, + this.enabled = true, + super.key, + }) : assert( + (initialSelectedDates?.length ?? 0) <= 1 || allowMultiSelect, + 'Wrong configuration allowMultiSelect=false and initialSelectedDates has multiple dates', + ); + /// Starting date of the week. final DateTime startingWeekDate; @@ -66,25 +89,9 @@ class ZdsDayPicker extends StatefulWidget { /// Defaults to true. final bool enabled; - /// Constructs a [ZdsDayPicker]. - const ZdsDayPicker({ - required this.startingWeekDate, - this.initialSelectedDates, - this.header, - this.allText, - this.disableDaysList = const [], - this.onDaySelected, - this.allowMultiSelect = false, - this.showInCard = true, - this.enabled = true, - super.key, - }) : assert( - (initialSelectedDates?.length ?? 0) <= 1 || allowMultiSelect, - 'Wrong configuration allowMultiSelect=false and initialSelectedDates has multiple dates', - ); - @override State createState() => _ZdsDayPickerState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -102,11 +109,11 @@ class ZdsDayPicker extends StatefulWidget { } class _ZdsDayPickerState extends State { - List weekDays = []; + List weekDays = []; int disabledCount = 0; bool isSelectedAllDay = false; - List selectedDates = []; - final dayPickerController = TextEditingController(); + List selectedDates = []; + final TextEditingController dayPickerController = TextEditingController(); @override void initState() { @@ -133,16 +140,16 @@ class _ZdsDayPickerState extends State { } void _updateDayController(List selectedDates) { - selectedDates.sort((first, next) => first.compareTo(next)); - final List dayBuffer = []; - for (final date in selectedDates) { + selectedDates.sort((DateTime first, DateTime next) => first.compareTo(next)); + final List dayBuffer = []; + for (final DateTime date in selectedDates) { dayBuffer.add(DateFormat('EEE').format(date)); } dayPickerController.value = dayPickerController.value.copyWith(text: dayBuffer.join(', ')); } void _computeWeekDaysDetails() { - weekDays = []; + weekDays = []; disabledCount = widget.disableDaysList.isEmpty ? 0 : widget.disableDaysList.length; for (int index = 0; index < 7; index++) { @@ -168,7 +175,7 @@ class _ZdsDayPickerState extends State { } else { if (selectedDayDetail.isChecked) { if (selectedDates.length == 1) { - for (final dayDetail in weekDays) { + for (final DayDetails dayDetail in weekDays) { if (selectedDayDetail.dayText != dayDetail.dayText && dayDetail.isChecked) { dayDetail.isChecked = false; selectedDates @@ -182,7 +189,7 @@ class _ZdsDayPickerState extends State { } } else { if (selectedDates.length > 1) { - for (final dayDetail in weekDays) { + for (final DayDetails dayDetail in weekDays) { if (selectedDayDetail.dayText != dayDetail.dayText) { dayDetail.isChecked = false; selectedDates.remove(DateUtils.dateOnly(dayDetail.date)); @@ -203,15 +210,15 @@ class _ZdsDayPickerState extends State { void selectAll() { setState(() { if ((selectedDates.length + widget.disableDaysList.length) == 7) { - selectedDates = []; - for (final dayDetail in weekDays) { + selectedDates = []; + for (final DayDetails dayDetail in weekDays) { if (!dayDetail.isDisabled) { dayDetail.isChecked = false; } } } else { - selectedDates = []; - for (final dayDetail in weekDays) { + selectedDates = []; + for (final DayDetails dayDetail in weekDays) { if (!dayDetail.isDisabled) { dayDetail.isChecked = true; selectedDates.add(dayDetail.date); @@ -226,22 +233,22 @@ class _ZdsDayPickerState extends State { @override Widget build(BuildContext context) { return LayoutBuilder( - builder: (context, constraints) { + builder: (BuildContext context, BoxConstraints constraints) { final double pillWidth = 68 * MediaQuery.of(context).textScaleFactor; - const pillSpacing = 4; + const int pillSpacing = 4; const double horizontalPadding = 12; - final totalLength = (weekDays.length * (pillWidth + pillSpacing)) + (horizontalPadding * 2); - final isWrapping = totalLength > constraints.maxWidth; + final double totalLength = (weekDays.length * (pillWidth + pillSpacing)) + (horizontalPadding * 2); + final bool isWrapping = totalLength > constraints.maxWidth; - final body = Row( - children: [ + final Row body = Row( + children: [ Expanded( child: Wrap( alignment: isWrapping ? WrapAlignment.start : WrapAlignment.center, - children: [ + children: [ ...weekDays.map( - (dayDetail) { + (DayDetails dayDetail) { return SizedBox( width: pillWidth, child: ZdsSelectionPill( @@ -262,14 +269,14 @@ class _ZdsDayPickerState extends State { ); return Column( - children: [ + children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + children: [ if (widget.header != null) Text( widget.header!, - style: Theme.of(context).textTheme.titleSmall, + style: Theme.of(context).textTheme.titleSmall?.copyWith(color: Zeta.of(context).colors.textDefault), ).paddingOnly(left: 6), if (widget.allowMultiSelect) SizedBox( @@ -309,8 +316,8 @@ class _ZdsDayPickerState extends State { } List getDatesOnly(List dateList) { - final List returnList = []; - for (final completeDate in dateList) { + final List returnList = []; + for (final DateTime completeDate in dateList) { returnList.add(DateUtils.dateOnly(completeDate)); } return returnList; diff --git a/lib/src/components/organisms/file_picker/file_annotations.dart b/lib/src/components/organisms/file_picker/file_annotations.dart index d780093..d0624bc 100644 --- a/lib/src/components/organisms/file_picker/file_annotations.dart +++ b/lib/src/components/organisms/file_picker/file_annotations.dart @@ -10,27 +10,18 @@ import '../../../../zds_flutter.dart'; /// Editors used to edit only image files & to launch other types of files class ZdsImageAnnotationPostProcessor implements ZdsFilePostProcessor { ///default constructor - ZdsImageAnnotationPostProcessor( - this.buildContext, { - this.initialCropAspectRatio = ZdsAspectRatio.ratio1x1, - }); + ZdsImageAnnotationPostProcessor(this.buildContext); ///Context used for navigations and toasts final BuildContextProvider buildContext; - /// Initial Aspect ratio of crop rect - /// default is [ZdsAspectRatio.original] - /// - /// The argument only affects the initial aspect ratio. - final ZdsAspectRatio initialCropAspectRatio; - @override Future process(FilePickerConfig config, FileWrapper file) async { if (kIsWeb) return file; if (file.isImage() && file.content != null) { - final originalFile = File(file.xFilePath); - final result = await _editFile(buildContext.call(), originalFile); + final File originalFile = File(file.xFilePath); + final XFile? result = await _editFile(buildContext.call(), originalFile); if (result != null) { return FileWrapper(file.type, result); } @@ -41,12 +32,15 @@ class ZdsImageAnnotationPostProcessor implements ZdsFilePostProcessor { Future _editFile(BuildContext context, File originalFile) async { ImageEditor.i18n(ComponentStrings.of(context).getAll()); - final bytes = await Navigator.push( - context, - MaterialPageRoute( + final bytes = await Navigator.of(context, rootNavigator: true).push( + ZdsFadePageRouteBuilder( + fullscreenDialog: true, builder: (context) { - return SingleImageEditor( + return ImageEditor( image: originalFile.readAsBytesSync(), + emojiOption: null, + textOption: null, + blurOption: null, ); }, ), @@ -54,7 +48,7 @@ class ZdsImageAnnotationPostProcessor implements ZdsFilePostProcessor { if (bytes != null) { await originalFile.delete(recursive: true); - final result = File(originalFile.path); + final File result = File(originalFile.path); await result.writeAsBytes(bytes); return ZdsXFile.fromFile(result); } else { diff --git a/lib/src/components/organisms/file_picker/file_compress.dart b/lib/src/components/organisms/file_picker/file_compress.dart index 2871a69..bb92f71 100644 --- a/lib/src/components/organisms/file_picker/file_compress.dart +++ b/lib/src/components/organisms/file_picker/file_compress.dart @@ -11,8 +11,8 @@ import '../../../utils/tools/utils.dart'; import '../temp_directory/resolver.dart'; import 'file_picker.dart'; -const _maxImageUploadSize = 256 * 1024; // 256 Kb -const _maxVideoUploadSize = 5 * 1024 * 1024; // 25 Mb +const int _maxImageUploadSize = 256 * 1024; // 256 Kb +const int _maxVideoUploadSize = 5 * 1024 * 1024; // 25 Mb /// Compressors for mobile devices @immutable @@ -38,10 +38,10 @@ class ZdsFileCompressPostProcessor implements ZdsFilePostProcessor { Future _compressVideo(File video, FilePickerConfig config) async { try { - final dir = await zdsTempDirectory(); - final fileExtension = path.extension(video.path).toLowerCase().replaceAll('.', ''); - final targetFile = File('$dir/${path.basenameWithoutExtension(video.path)}.$fileExtension'); - final maxFileSize = config.maxFileSize == 0 ? _maxVideoUploadSize : config.maxFileSize; + final String dir = await zdsTempDirectory(); + final String fileExtension = path.extension(video.path).toLowerCase().replaceAll('.', ''); + final File targetFile = File('$dir/${path.basenameWithoutExtension(video.path)}.$fileExtension'); + final int maxFileSize = config.maxFileSize == 0 ? _maxVideoUploadSize : config.maxFileSize; File compressedVideo; try { @@ -56,9 +56,9 @@ class ZdsFileCompressPostProcessor implements ZdsFilePostProcessor { compressedVideo = video; } - final size = await compressedVideo.length(); + final int size = await compressedVideo.length(); if (size > maxFileSize) { - throw FilePickerException(PickerExceptionType.maxFileSize, args: [fileSizeWithUnit(maxFileSize)]); + throw FilePickerException(PickerExceptionType.maxFileSize, args: [fileSizeWithUnit(maxFileSize)]); } return ZdsXFile.fromFile(compressedVideo); @@ -68,7 +68,7 @@ class ZdsFileCompressPostProcessor implements ZdsFilePostProcessor { } VideoQuality _videoQuality(int config) { - const qualityMap = { + const Map qualityMap = { 1: VideoQuality.Res1280x720Quality, 2: VideoQuality.Res960x540Quality, 3: VideoQuality.Res640x480Quality, @@ -81,13 +81,13 @@ class ZdsFileCompressPostProcessor implements ZdsFilePostProcessor { Future _compressImage(File image, FilePickerConfig config) async { try { - final fileSize = config.maxFileSize == 0 ? _maxImageUploadSize : config.maxFileSize; - final h = config.maxPixelSize <= 0 ? 1080 : config.maxPixelSize; + final int fileSize = config.maxFileSize == 0 ? _maxImageUploadSize : config.maxFileSize; + final int h = config.maxPixelSize <= 0 ? 1080 : config.maxPixelSize; // Resolve compression type - final fileExtension = path.extension(image.path).toLowerCase().replaceAll('.', ''); - final format = _getCompressFormat(fileExtension, config); - final quality = h < 1000 + final String fileExtension = path.extension(image.path).toLowerCase().replaceAll('.', ''); + final CompressFormat? format = _getCompressFormat(fileExtension, config); + final int quality = h < 1000 ? 95 : h < 1500 ? 75 @@ -97,8 +97,9 @@ class ZdsFileCompressPostProcessor implements ZdsFilePostProcessor { if (format != null) { try { - final c = Compression(maxFileSize: fileSize, minHeight: h, minWidth: h, format: format, quality: quality); - var compressed = await ZdsCompressor.compressImage(image: image, compression: c); + final Compression c = + Compression(maxFileSize: fileSize, minHeight: h, minWidth: h, format: format, quality: quality); + File? compressed = await ZdsCompressor.compressImage(image: image, compression: c); if (compressed != null) { // Rename file back to jpg if picked file was jpg and allowed file types dose not contain jpeg. // This step is needed as jpg is compressed to jpeg @@ -116,7 +117,7 @@ class ZdsFileCompressPostProcessor implements ZdsFilePostProcessor { final int size = await result.length(); if (size > fileSize) { - throw FilePickerException(PickerExceptionType.maxFileSize, args: [fileSizeWithUnit(fileSize)]); + throw FilePickerException(PickerExceptionType.maxFileSize, args: [fileSizeWithUnit(fileSize)]); } return ZdsXFile.fromFile(result); @@ -126,7 +127,7 @@ class ZdsFileCompressPostProcessor implements ZdsFilePostProcessor { } CompressFormat? _getCompressFormat(String extension, FilePickerConfig config) { - final allowedExt = config.allowedExtensions.map((e) => e.toLowerCase()); + final Iterable allowedExt = config.allowedExtensions.map((String e) => e.toLowerCase()); // If allowed file extension list is empty then return jpeg if (allowedExt.isEmpty) return CompressFormat.jpeg; diff --git a/lib/src/components/organisms/file_picker/file_edit.dart b/lib/src/components/organisms/file_picker/file_edit.dart index 32c41b7..ab17e93 100644 --- a/lib/src/components/organisms/file_picker/file_edit.dart +++ b/lib/src/components/organisms/file_picker/file_edit.dart @@ -5,48 +5,42 @@ import 'package:flutter/material.dart'; import 'package:image_editor_plus/image_editor_plus.dart'; import 'package:path/path.dart' as path; -import '../../../../zds_flutter.dart'; +import '../../../../../zds_flutter.dart'; import '../temp_directory/resolver.dart'; /// Editors used to edit only image files & to launch other types of files class ZdsFileEditPostProcessor implements ZdsFilePostProcessor { ///default constructor - ZdsFileEditPostProcessor( - this.buildContext, { - this.initialCropAspectRatio = ZdsAspectRatio.ratio1x1, - }); + ZdsFileEditPostProcessor(this.buildContext); ///Context used for navigations and toasts final BuildContextProvider buildContext; - /// Initial Aspect ratio of crop rect - /// default is [ZdsAspectRatio.original] - /// - /// The argument only affects the initial aspect ratio. - final ZdsAspectRatio initialCropAspectRatio; - @override Future process(FilePickerConfig config, FileWrapper file) async { if (kIsWeb) return file; if (file.isImage() && file.content != null) { - final originalFile = File(file.xFilePath); + final File originalFile = File(file.xFilePath); ImageEditor.i18n(ComponentStrings.of(buildContext.call()).getAll()); - final bytes = await Navigator.push( - buildContext.call(), - MaterialPageRoute( + final bytes = await Navigator.of(buildContext.call(), rootNavigator: true).push( + ZdsFadePageRouteBuilder( + fullscreenDialog: true, builder: (context) { - return SingleImageEditor( + return ImageEditor( image: originalFile.readAsBytesSync(), + emojiOption: null, + textOption: null, + blurOption: null, ); }, ), ); if (bytes != null) { - final dir = await zdsTempDirectory('edited'); + final String dir = await zdsTempDirectory('edited'); await originalFile.delete(recursive: true); - final result = File(path.join(dir, path.basename(originalFile.absolute.path))); + final File result = File(path.join(dir, path.basename(originalFile.absolute.path))); await result.writeAsBytes(bytes); return FileWrapper(file.type, ZdsXFile.fromFile(result)); } diff --git a/lib/src/components/organisms/file_picker/file_picker.dart b/lib/src/components/organisms/file_picker/file_picker.dart index 6338919..f4e87a7 100644 --- a/lib/src/components/organisms/file_picker/file_picker.dart +++ b/lib/src/components/organisms/file_picker/file_picker.dart @@ -1,21 +1,31 @@ -// TODO(thelukewalton): throwing error on mac - import 'dart:async'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_swipe_action_cell/flutter_swipe_action_cell.dart'; -import 'package:giphy_get/giphy_get.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; import 'package:open_filex/open_filex.dart'; import 'package:universal_platform/universal_platform.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../../zds_flutter.dart' hide ImagePicker; +import '../../../utils/assets/icons.dart'; +import '../../../utils/localizations/translation.dart'; +import '../../../utils/theme/input_border.dart'; +import '../../../utils/tools/modifiers.dart'; +import '../../../utils/tools/utils.dart'; +import '../../atoms/absorb_pointer.dart'; +import '../../atoms/button.dart'; +import '../../atoms/card.dart'; +import '../../molecules/list.dart'; +import '../file_preview.dart'; +import '../list_tile.dart'; +import 'file_picker.dart'; import 'giphy_picker.dart'; +export 'package:giphy_get/giphy_get.dart'; + export 'file_post_processor.dart'; export 'file_validator.dart'; export 'file_wrapper.dart'; @@ -28,6 +38,7 @@ typedef ZdsFileValidator = Future Function( ZdsFilePickerController controller, FilePickerConfig config, FileWrapper fileWrapper, + FilePickerOptions option, ); /// The configuration used in a [ZdsFilePicker]. @@ -39,6 +50,26 @@ typedef ZdsFileValidator = Future Function( /// /// * [ZdsFilePicker] class FilePickerConfig { + /// Creates the configuration to use in the [ZdsFilePicker]. + const FilePickerConfig({ + this.videoCompressionLevel = 3, + this.maxFilesAllowed = 0, + this.maxFileSize = 0, + this.maxPixelSize = 0, + this.allowedExtensions = const {}, + this.useLiveMediaOnly = false, + this.options = const [ + FilePickerOptions.VIDEO, + FilePickerOptions.FILE, + FilePickerOptions.CAMERA, + FilePickerOptions.GALLERY, + ], + this.giphyApiKey, + }) : assert(maxPixelSize >= 0, 'maxPixelSize must be greater than or equal to 0'), + assert(maxFileSize >= 0, 'maxFileSize must be greater than or equal to 0'); + + /// Creates the configuration to use in the [ZdsFilePicker]. + /// The maximum number of files allowed. /// /// Defaults to 0. @@ -49,6 +80,12 @@ class FilePickerConfig { /// If empty, all files are allowed. Defaults to empty. final Set allowedExtensions; + /// The [useLiveMediaOnly]. flag use to disable photo library/gallery or file browser option. + /// If `true` then we disable all photos & videos from file picker a the time of validation + /// If `false`, all files are allowed. which are available in [allowedExtensions]. + /// Defaults to false. + final bool useLiveMediaOnly; + /// If the file picked is an image, its maximum side dimension once it's been selected. /// /// If 0, it will be unlimited. Defaults to unlimited size. @@ -80,26 +117,9 @@ class FilePickerConfig { /// API Key, required to use giphy service. /// - /// See https://developers.giphy.com/ + /// See [Giphy Developers](https://developers.giphy.com/) final String? giphyApiKey; - /// Creates the configuration to use in the [ZdsFilePicker]. - const FilePickerConfig({ - this.videoCompressionLevel = 3, - this.maxFilesAllowed = 0, - this.maxFileSize = 0, - this.maxPixelSize = 0, - this.allowedExtensions = const {}, - this.giphyApiKey, - this.options = const [ - FilePickerOptions.VIDEO, - FilePickerOptions.FILE, - FilePickerOptions.CAMERA, - FilePickerOptions.GALLERY, - ], - }) : assert(maxPixelSize >= 0, 'maxPixelSize must be greater than or equal to 0'), - assert(maxFileSize >= 0, 'maxFileSize must be greater than or equal to 0'); - /// Creates a copy of this [FilePickerConfig], but with the given fields replaced wih the new values. FilePickerConfig copyWith({ int? videoCompressionLevel, @@ -107,6 +127,7 @@ class FilePickerConfig { int? maxFileSize, int? maxPixelSize, Set? allowedExtensions, + bool? useLiveMediaOnly, List? options, }) { return FilePickerConfig( @@ -116,6 +137,7 @@ class FilePickerConfig { maxPixelSize: maxPixelSize ?? this.maxPixelSize, allowedExtensions: allowedExtensions ?? this.allowedExtensions, options: options ?? this.options, + useLiveMediaOnly: useLiveMediaOnly ?? this.useLiveMediaOnly, ); } @@ -170,6 +192,23 @@ enum ZdsOptionDisplay { /// * [ImagePicker], a widget used to select a single image and show its preview. /// * [ZdsFilePreview], which this component uses to show previews of the selected files. class ZdsFilePicker extends StatefulWidget { + /// Creates a component that allows to select files and can display a preview of the selected files. + const ZdsFilePicker({ + required this.controller, + super.key, + this.onChange, + this.config = const FilePickerConfig(), + this.displayStyle = ZdsFilePickerDisplayStyle.vertical, + this.validator = zdsValidator, + this.onError = zdsFileError, + this.postProcessors = zdsDefaultPostProcessors, + this.optionDisplay = ZdsOptionDisplay.standard, + this.showLinkName = true, + this.showSelected = true, + this.useCard = true, + this.visualDensity = VisualDensity.standard, + }); + /// Whether to use a default card background. If false, uses a transparent background. /// /// Defaults to true. @@ -222,45 +261,30 @@ class ZdsFilePicker extends StatefulWidget { /// Defaults to [zds FileError] final void Function(BuildContext context, FilePickerConfig config, Exception exception)? onError; - /// Creates a component that allows to select files and can display a preview of the selected files. - const ZdsFilePicker({ - required this.controller, - super.key, - this.onChange, - this.config = const FilePickerConfig(), - this.displayStyle = ZdsFilePickerDisplayStyle.vertical, - this.validator = zdsValidator, - this.onError = zdsFileError, - this.postProcessors = zdsDefaultPostProcessors, - this.optionDisplay = ZdsOptionDisplay.standard, - this.showLinkName = true, - this.showSelected = true, - this.useCard = true, - this.visualDensity = VisualDensity.standard, - }); - @override ZdsFilePickerState createState() => ZdsFilePickerState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('useCard', useCard)); - properties.add(DiagnosticsProperty('showSelected', showSelected)); - properties.add(EnumProperty('optionDisplay', optionDisplay)); - properties.add(EnumProperty('displayStyle', displayStyle)); - properties.add(DiagnosticsProperty('visualDensity', visualDensity)); - properties.add(DiagnosticsProperty('config', config)); - properties.add(DiagnosticsProperty('controller', controller)); - properties.add(ObjectFlagProperty items)?>.has('onChange', onChange)); - properties.add(DiagnosticsProperty('showLinkName', showLinkName)); - properties.add(IterableProperty('postProcessors', postProcessors)); - properties.add(ObjectFlagProperty.has('validator', validator)); - properties.add( - ObjectFlagProperty.has( - 'onError', - onError, - ), - ); + properties + ..add(DiagnosticsProperty('useCard', useCard)) + ..add(DiagnosticsProperty('showSelected', showSelected)) + ..add(EnumProperty('optionDisplay', optionDisplay)) + ..add(EnumProperty('displayStyle', displayStyle)) + ..add(DiagnosticsProperty('visualDensity', visualDensity)) + ..add(DiagnosticsProperty('config', config)) + ..add(DiagnosticsProperty('controller', controller)) + ..add(ObjectFlagProperty items)?>.has('onChange', onChange)) + ..add(DiagnosticsProperty('showLinkName', showLinkName)) + ..add(IterableProperty('postProcessors', postProcessors)) + ..add(ObjectFlagProperty.has('validator', validator)) + ..add( + ObjectFlagProperty.has( + 'onError', + onError, + ), + ); } } @@ -284,7 +308,7 @@ class ZdsFilePickerState extends State with AutomaticKeepAliveCli FilePickerConfig get config => widget.config; List get _allowedOptions { - final list = [...config.options]; + final List list = [...config.options]; if (config.giphyApiKey == null || config.giphyApiKey!.isEmpty) { list.remove(FilePickerOptions.GIF); } @@ -306,21 +330,21 @@ class ZdsFilePickerState extends State with AutomaticKeepAliveCli @override Widget build(BuildContext context) { super.build(context); - final maxFiles = config.maxFilesAllowed; - final busy = _busy || controller.busy; - final attachmentList = controller.items.where((element) => !element.isLink).toList(); - final disableWidget = _busy || controller.busy || (maxFiles != 0 && maxFiles <= attachmentList.length); - final content = AnimatedSize( + final int maxFiles = config.maxFilesAllowed; + final bool busy = _busy || controller.busy; + final List attachmentList = controller.items.where((FileWrapper element) => !element.isLink).toList(); + final bool disableWidget = _busy || controller.busy || (maxFiles != 0 && maxFiles <= attachmentList.length); + final AnimatedSize content = AnimatedSize( duration: const Duration(milliseconds: 250), child: Stack( alignment: Alignment.center, - children: [ + children: [ ZdsAbsorbPointer( absorbing: busy, child: Column( mainAxisSize: MainAxisSize.min, - children: [ - if (widget.showSelected && (controller.items.isNotEmpty)) ...[ + children: [ + if (widget.showSelected && (controller.items.isNotEmpty)) ...[ _buildAttachments(), if (widget.displayStyle == ZdsFilePickerDisplayStyle.vertical) const Divider(), ], @@ -329,7 +353,7 @@ class ZdsFilePickerState extends State with AutomaticKeepAliveCli child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: _allowedOptions - .map((option) => _buildOption(context, option)) + .map((FilePickerOptions option) => _buildOption(context, option)) .toList() .divide(_divider) .toList(), @@ -357,17 +381,17 @@ class ZdsFilePickerState extends State with AutomaticKeepAliveCli return SizedBox( height: height, child: Builder( - builder: (context) { + builder: (BuildContext context) { return DefaultTextStyle( style: Theme.of(context).textTheme.bodySmall!, child: ZdsHorizontalList.builder( isReducedHeight: true, itemCount: controller.items.length, - itemBuilder: (context, index) { - final fileWrapper = controller.items[index]; + itemBuilder: (BuildContext context, int index) { + final FileWrapper fileWrapper = controller.items[index]; return Column( mainAxisSize: MainAxisSize.min, - children: [ + children: [ ZdsFilePreview( file: fileWrapper, size: height * 0.7, @@ -394,15 +418,15 @@ class ZdsFilePickerState extends State with AutomaticKeepAliveCli itemCount: controller.items.length, separatorBuilder: (_, __) => const Divider(), physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - final wrapper = controller.items[index]; + itemBuilder: (BuildContext context, int index) { + final FileWrapper wrapper = controller.items[index]; return SwipeActionCell( key: ObjectKey(wrapper.hashCode), backgroundColor: Theme.of(context).colorScheme.surface, - trailingActions: [ + trailingActions: [ SwipeAction( color: Theme.of(context).colorScheme.error, - onTap: (handler) async => controller.openFile(context, config, wrapper), + onTap: (_) async => controller.openFile(context, config, wrapper), content: Semantics( focused: true, label: ComponentStrings.of(context).get('DELETE', 'Delete'), @@ -416,7 +440,6 @@ class ZdsFilePickerState extends State with AutomaticKeepAliveCli child: Semantics( hint: ComponentStrings.of(context).get('SWIPE_TO_REVEAL_SEMANTIC', 'Swipe left to reveal actions'), child: ZdsListTile( - shrinkWrap: true, leading: ZdsFilePreview(file: wrapper, size: 50, useCard: false), onTap: () async => controller.openFile(context, config, wrapper), title: Text( @@ -445,17 +468,19 @@ class ZdsFilePickerState extends State with AutomaticKeepAliveCli @override bool get wantKeepAlive => true; + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('controller', controller)); - properties.add(DiagnosticsProperty('config', config)); + properties + ..add(DiagnosticsProperty('controller', controller)) + ..add(DiagnosticsProperty('config', config)); } } extension _FileWrapperIcon on FilePickerOptions { IconData get icon { - final Map map = { + final Map map = { FilePickerOptions.FILE: ZdsIcons.upload, FilePickerOptions.LINK: ZdsIcons.add_link, FilePickerOptions.GALLERY: ZdsIcons.image, @@ -468,7 +493,7 @@ extension _FileWrapperIcon on FilePickerOptions { } String getLabel(BuildContext context) { - final Map map = { + final Map map = { FilePickerOptions.FILE: ComponentStrings.of(context).get('FILE', 'File'), FilePickerOptions.LINK: ComponentStrings.of(context).get('LINK', 'Link'), FilePickerOptions.GALLERY: ComponentStrings.of(context).get('GALLERY', 'Gallery'), @@ -493,15 +518,16 @@ extension _Methods on ZdsFilePickerState { await _handleVideoAction(context); } else if (option == FilePickerOptions.CAMERA) { await _handleCameraAction(context); - } else if (option == FilePickerOptions.GIF) { + } else if (option == FilePickerOptions.GIF && config.giphyApiKey != null && config.giphyApiKey!.isNotEmpty) { await _handleGifAction(context); } } Future _handleLinkAction(BuildContext context) async { String? isValidUrl(Uri? uri) { - final urlExp = RegExp(r'(http|ftp|https)://[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?'); - final url = uri.toString(); + final RegExp urlExp = + RegExp(r'(http|ftp|https)://[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?'); + final String url = uri.toString(); if (uri == null || !uri.isAbsolute || !urlExp.hasMatch(url)) { return ComponentStrings.of(context).get('URL_INVALID_ER', 'Please enter valid URL.'); } else { @@ -509,21 +535,21 @@ extension _Methods on ZdsFilePickerState { } } - final result = await showDialog?>( + final List<_TextField>? result = await showDialog?>( context: context, barrierDismissible: false, builder: (BuildContext context) { - final strings = ComponentStrings.of(context); + final ComponentStrings strings = ComponentStrings.of(context); return _MultiInputDialog( title: strings.get('ADD_URL', 'Add url'), - textFields: [ + textFields: <_TextField>[ if (widget.showLinkName) _TextField(id: 'name', hint: strings.get('LINK_NAME', 'Link Name'), autoFocus: true), _TextField(id: 'url', hint: strings.get('LINK_URL', 'Link URL'), autoFocus: true), ], primaryAction: strings.get('SAVE', 'Save'), secondaryAction: strings.get('CANCEL', 'Cancel'), - onValidate: (field) { + onValidate: (_TextField field) { if (field.id == 'url') { return isValidUrl(Uri.tryParse(field.value)); } else { @@ -535,12 +561,12 @@ extension _Methods on ZdsFilePickerState { ); if (result != null) { - final urlField = result.last; - final nameField = result.length == 2 ? result.first : null; - final uri = Uri.tryParse(urlField.value); + final _TextField urlField = result.last; + final _TextField? nameField = result.length == 2 ? result.first : null; + final Uri? uri = Uri.tryParse(urlField.value); if (uri != null) { - final name = nameField?.value ?? ''; - controller.addFiles([ + final String name = nameField?.value ?? ''; + controller.addFiles([ FileWrapper(FilePickerOptions.LINK, XUri(uri: uri, name: name.isEmpty ? uri.toString() : name)), ]); } @@ -551,14 +577,13 @@ extension _Methods on ZdsFilePickerState { final GiphyGif? gif = await Navigator.push( context, MaterialPageRoute( - builder: (context) => ZdsGiphyPicker(apiKey: config.giphyApiKey ?? ''), + builder: (BuildContext context) => ZdsGiphyPicker(apiKey: config.giphyApiKey!), ), ); - try { if (gif == null) return; _busy = true; - if (mounted) await onPicked(context, FileWrapper(FilePickerOptions.GIF, gif)); + if (mounted) await onPicked(context, FileWrapper(FilePickerOptions.GIF, gif), FilePickerOptions.GIF); } on Exception catch (e) { if (mounted) widget.onError?.call(context, config, e); } finally { @@ -569,10 +594,10 @@ extension _Methods on ZdsFilePickerState { Future _handleCameraAction(BuildContext context) async { try { final ImagePicker picker = ImagePicker(); - final photo = await picker.pickImage(source: ImageSource.camera); + final XFile? photo = await picker.pickImage(source: ImageSource.camera); if (photo != null && mounted) { final FileWrapper file = FileWrapper(FilePickerOptions.CAMERA, photo); - await onPicked(context, file); + await onPicked(context, file, FilePickerOptions.CAMERA); } } on Exception catch (e) { if (mounted) widget.onError?.call(context, config, e); @@ -584,11 +609,11 @@ extension _Methods on ZdsFilePickerState { Future _handleVideoAction(BuildContext context) async { try { final ImagePicker picker = ImagePicker(); - final video = await picker.pickVideo(source: ImageSource.camera); + final XFile? video = await picker.pickVideo(source: ImageSource.camera); if (video != null && mounted) { final FileWrapper file = FileWrapper(FilePickerOptions.VIDEO, video); - await onPicked(context, file); + await onPicked(context, file, FilePickerOptions.VIDEO); } } on Exception catch (e) { if (mounted) widget.onError?.call(context, config, e); @@ -602,10 +627,10 @@ extension _Methods on ZdsFilePickerState { /// Allow to pick media if allowed extensions are empty. /// Else checks based on allowed types. Future _handleGalleryAction(BuildContext context) async { - var fileType = FileType.media; + FileType fileType = FileType.media; - final allowImages = config.allowImages(); - final allowVideos = config.allowVideos(); + final bool allowImages = config.allowImages(); + final bool allowVideos = config.allowVideos(); if (allowImages && allowVideos) { fileType = FileType.media; @@ -626,7 +651,12 @@ extension _Methods on ZdsFilePickerState { FilePickerOptions option = FilePickerOptions.FILE, }) async { try { - final allowedFileExt = Set.from(config.allowedExtensions); + final allowedFileExt = Set.from( + getAllowedFileBrowserTypes( + useLiveMediaOnly: config.useLiveMediaOnly, + allowedFileTypes: config.allowedExtensions, + ), + ); final maxFilesAllowed = config.maxFilesAllowed; final allowMultiple = maxFilesAllowed == 0 || maxFilesAllowed > 1; final mutableType = type == FileType.any @@ -637,10 +667,10 @@ extension _Methods on ZdsFilePickerState { _busy = true; - final result = mutableType == FileType.custom + final FilePickerResult? result = mutableType == FileType.custom ? await FilePicker.platform.pickFiles( type: mutableType, - allowedExtensions: List.from(allowedFileExt), + allowedExtensions: List.from(allowedFileExt), allowMultiple: allowMultiple, ) : await FilePicker.platform.pickFiles( @@ -649,17 +679,19 @@ extension _Methods on ZdsFilePickerState { ); if (result != null && mounted) { - for (final file in result.files) { + for (final PlatformFile file in result.files) { if (maxFilesAllowed != 0 && - controller.items.where((element) => !element.isLink).toList().length >= maxFilesAllowed) break; + controller.items.where((FileWrapper element) => !element.isLink).toList().length >= maxFilesAllowed) { + break; + } if (kIsWeb) { - final mimeType = lookupMimeType(file.name); - final xfile = XFile.fromData(file.bytes!, name: file.name, length: file.size, mimeType: mimeType); - await onPicked(context, FileWrapper(option, xfile)); + final String? mimeType = lookupMimeType(file.name); + final XFile xfile = XFile.fromData(file.bytes!, name: file.name, length: file.size, mimeType: mimeType); + await onPicked(context, FileWrapper(option, xfile), option); } else { - final mimeType = lookupMimeType(file.path ?? ''); - final xfile = XFile(file.path!, name: file.name, length: file.size, mimeType: mimeType); - await onPicked(context, FileWrapper(option, xfile)); + final String? mimeType = lookupMimeType(file.path ?? ''); + final XFile xfile = XFile(file.path!, name: file.name, length: file.size, mimeType: mimeType); + await onPicked(context, FileWrapper(option, xfile), option); } } } @@ -670,16 +702,20 @@ extension _Methods on ZdsFilePickerState { } } - Future onPicked(BuildContext context, FileWrapper file) async { + Future onPicked( + BuildContext context, + FileWrapper file, + FilePickerOptions option, + ) async { try { if (file.content == null) return; _busy = true; - final exception = await widget.validator?.call(controller, config, file); + final FilePickerException? exception = await widget.validator?.call(controller, config, file, option); - var input = file; + FileWrapper input = file; if (exception == null && widget.postProcessors != null) { - for (final p in widget.postProcessors!) { + for (final ZdsFilePostProcessor p in widget.postProcessors!) { input = await p.process(config, input); } } @@ -687,7 +723,7 @@ extension _Methods on ZdsFilePickerState { if (exception != null && mounted) { widget.onError?.call(context, config, exception); } else { - controller.addFiles([input]); + controller.addFiles([input]); } } on Exception catch (e) { if (mounted) widget.onError?.call(context, config, e); @@ -704,7 +740,7 @@ extension on ZdsFilePickerState { height: widget.visualDensity == VisualDensity.standard ? 40 : 26, decoration: BoxDecoration( border: Border( - left: BorderSide(color: ZdsColors.greySwatch(context)[400] ?? ZdsColors.lightGrey), + left: BorderSide(color: Zeta.of(context).colors.borderSubtle), ), ), ) @@ -713,10 +749,11 @@ extension on ZdsFilePickerState { Widget _buildOption(BuildContext context, FilePickerOptions option) { final bool isStandard = widget.visualDensity == VisualDensity.standard; - final style = isStandard + final TextStyle? style = isStandard ? Theme.of(context).textTheme.bodyMedium : Theme.of(context).textTheme.bodyMedium?.copyWith(fontSize: 12, height: 16 / 12); - final padding = 16 + ((widget.visualDensity?.vertical ?? 0) * 4); + final double padding = 16 + ((widget.visualDensity?.vertical ?? 0) * 4); + final zetaColors = Zeta.of(context).colors; return Expanded( child: Semantics( button: true, @@ -731,19 +768,19 @@ extension on ZdsFilePickerState { : 30, onTap: () async => handleOptionAction(context, option), child: Column( - children: [ + children: [ Icon( option.icon, size: 24 + ((widget.visualDensity?.vertical ?? 0) * 4), - color: ZetaColors.of(context).textSubtle, + color: zetaColors.iconSubtle, ), - if (widget.optionDisplay == ZdsOptionDisplay.standard) ...[ + if (widget.optionDisplay == ZdsOptionDisplay.standard) ...[ SizedBox(height: 10 + ((widget.visualDensity?.vertical ?? 0) * 4)), Text( option.getLabel(context), maxLines: 1, overflow: TextOverflow.ellipsis, - style: style?.copyWith(color: ZdsColors.greySwatch(context)[800]), + style: style?.copyWith(color: zetaColors.textSubtle), textScaleFactor: MediaQuery.of(context).textScaleFactor > 2.7 ? 2.7 : null, ), ], @@ -773,10 +810,10 @@ class ZdsFilePickerController extends ChangeNotifier { } /// The selected files. - List items = []; + List items = []; /// file from server to check itemCount only - List remoteItems = []; + List remoteItems = []; /// Programmatically adds a list of files to the linked [ZdsFilePicker]. void addFiles(List files) { @@ -786,7 +823,7 @@ class ZdsFilePickerController extends ChangeNotifier { /// Programmatically removes files from the linked [ZdsFilePicker]. int removeFile(FileWrapper file, {bool notify = true}) { - final index = items.indexWhere((element) => element == file); + final int index = items.indexWhere((FileWrapper element) => element == file); if (index >= 0) { items.removeAt(index); if (notify) notifyListeners(); @@ -800,15 +837,15 @@ class ZdsFilePickerController extends ChangeNotifier { /// Opens links in an InAppWebView, otherwise opens the file using the native viewer. Future openFile(BuildContext context, FilePickerConfig config, FileWrapper file) async { if (file.content != null && file.content is XFile) { - final fileToOpen = file.content as XFile; + final XFile fileToOpen = file.content as XFile; if (file.isImage()) { // Edit the file - final editPostProcessor = ZdsFileEditPostProcessor(() => context); - final editedFile = await editPostProcessor.process(config, file); + final ZdsFileEditPostProcessor editPostProcessor = ZdsFileEditPostProcessor(() => context); + final FileWrapper editedFile = await editPostProcessor.process(config, file); if (editedFile.content != file.content) { - const compressPostProcessor = ZdsFileCompressPostProcessor(); - final compressedFile = await compressPostProcessor.process(config, editedFile); - final index = removeFile(file); + const ZdsFileCompressPostProcessor compressPostProcessor = ZdsFileCompressPostProcessor(); + final FileWrapper compressedFile = await compressPostProcessor.process(config, editedFile); + final int index = removeFile(file); items.insert(index, compressedFile); notifyListeners(); } @@ -830,12 +867,6 @@ class _TextField { } class _MultiInputDialog extends StatefulWidget { - final String? title; - final String primaryAction; - final String? secondaryAction; - final List<_TextField> textFields; - final String? Function(_TextField)? onValidate; - const _MultiInputDialog({ required this.textFields, required this.primaryAction, @@ -844,25 +875,34 @@ class _MultiInputDialog extends StatefulWidget { this.onValidate, }); + final String? title; + final String primaryAction; + final String? secondaryAction; + final List<_TextField> textFields; + final String? Function(_TextField)? onValidate; + @override _MultiInputDialogState createState() => _MultiInputDialogState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('title', title)); - properties.add(StringProperty('primaryAction', primaryAction)); - properties.add(StringProperty('secondaryAction', secondaryAction)); - properties.add(IterableProperty<_TextField>('textFields', textFields)); - properties.add(ObjectFlagProperty.has('onValidate', onValidate)); + properties + ..add(StringProperty('title', title)) + ..add(StringProperty('primaryAction', primaryAction)) + ..add(StringProperty('secondaryAction', secondaryAction)) + ..add(IterableProperty<_TextField>('textFields', textFields)) + ..add(ObjectFlagProperty.has('onValidate', onValidate)); } } class _MultiInputDialogState extends State<_MultiInputDialog> { - bool get isValid => widget.textFields.fold(true, (p, r) => p && (widget.onValidate?.call(r) == null)); + bool get isValid => + widget.textFields.fold(true, (bool p, _TextField r) => p && (widget.onValidate?.call(r) == null)); @override Widget build(BuildContext context) { - final theme = Theme.of(context); + final ThemeData theme = Theme.of(context); return Dialog( child: Container( @@ -872,7 +912,7 @@ class _MultiInputDialogState extends State<_MultiInputDialog> { child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ + children: [ if (widget.title != null) Text(widget.title!, style: theme.textTheme.displaySmall), if (widget.textFields.isEmpty) const SizedBox(), ListView.builder( @@ -881,21 +921,22 @@ class _MultiInputDialogState extends State<_MultiInputDialog> { padding: const EdgeInsets.symmetric(vertical: 8), itemCount: widget.textFields.length, itemBuilder: (BuildContext context, int index) { + final themeData = Theme.of(context); return TextFormField( autofocus: widget.textFields[index].autoFocus, textInputAction: TextInputAction.done, autovalidateMode: AutovalidateMode.onUserInteraction, - onChanged: (value) { + onChanged: (String value) { setState(() { widget.textFields[index].value = value; }); }, - onFieldSubmitted: (value) => widget.textFields[index].value = value, - validator: (value) => widget.onValidate?.call(widget.textFields[index]), + onFieldSubmitted: (String value) => widget.textFields[index].value = value, + validator: (String? value) => widget.onValidate?.call(widget.textFields[index]), decoration: ZdsInputDecoration( hintText: widget.textFields[index].hint, errorText: widget.textFields[index].error, - errorStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(color: ZdsColors.red), + errorStyle: themeData.textTheme.bodyMedium?.copyWith(color: themeData.colorScheme.error), ), ); }, diff --git a/lib/src/components/organisms/file_picker/file_post_processor.dart b/lib/src/components/organisms/file_picker/file_post_processor.dart index b147d4b..3cf14f0 100644 --- a/lib/src/components/organisms/file_picker/file_post_processor.dart +++ b/lib/src/components/organisms/file_picker/file_post_processor.dart @@ -5,6 +5,7 @@ import 'file_picker.dart'; export 'file_compress.dart'; export 'file_edit.dart'; export 'file_rename.dart'; +export 'image_crop.dart'; /// Context used for page navigation typedef BuildContextProvider = BuildContext Function(); @@ -17,4 +18,7 @@ abstract class ZdsFilePostProcessor { } /// Default post processors -const zdsDefaultPostProcessors = [ZdsFileCompressPostProcessor(), ZdsFileRenamePostProcessor()]; +const List zdsDefaultPostProcessors = [ + ZdsFileCompressPostProcessor(), + ZdsFileRenamePostProcessor(), +]; diff --git a/lib/src/components/organisms/file_picker/file_rename.dart b/lib/src/components/organisms/file_picker/file_rename.dart index 18d5d12..f900abf 100644 --- a/lib/src/components/organisms/file_picker/file_rename.dart +++ b/lib/src/components/organisms/file_picker/file_rename.dart @@ -15,11 +15,11 @@ class ZdsFileRenamePostProcessor implements ZdsFilePostProcessor { @override Future process(FilePickerConfig config, FileWrapper file) async { if (kIsWeb || file.content is! XFile) return file; - final photoDir = path.dirname(file.xFilePath); - final epoch = DateFormat('yyyyMMdd_HHmmssSSS').format(DateTime.now()); - final fileName = '${file.type.toPrefix()}_$epoch${path.extension(file.xFilePath)}'; - final newPath = path.join(photoDir, fileName); - final photoFile = File(file.xFilePath).renameSync(newPath); + final String photoDir = path.dirname(file.xFilePath); + final String epoch = DateFormat('yyyyMMdd_HHmmssSSS').format(DateTime.now()); + final String fileName = '${file.type.toPrefix()}_$epoch${path.extension(file.xFilePath)}'; + final String newPath = path.join(photoDir, fileName); + final File photoFile = File(file.xFilePath).renameSync(newPath); return FileWrapper(file.type, ZdsXFile.fromFile(photoFile)); } } diff --git a/lib/src/components/organisms/file_picker/file_validator.dart b/lib/src/components/organisms/file_picker/file_validator.dart index 027916c..625df81 100644 --- a/lib/src/components/organisms/file_picker/file_validator.dart +++ b/lib/src/components/organisms/file_picker/file_validator.dart @@ -9,14 +9,14 @@ import 'file_picker.dart'; /// Class defining different exceptions types with its arguments class FilePickerException implements Exception { + /// Default constructor + FilePickerException(this.type, {this.args = const []}); + /// Used to specify different types of errors PickerExceptionType type; /// Used to specify custom error sizes List args; - - /// Default constructor - FilePickerException(this.type, {this.args = const []}); } /// Types of errors, commonly used to generate error toast messages later @@ -60,10 +60,23 @@ Future zdsValidator( ZdsFilePickerController controller, FilePickerConfig config, FileWrapper wrapper, + FilePickerOptions option, ) async { - final file = wrapper.content; + final dynamic file = wrapper.content; if (file is! XFile) return null; + //file type check if [useLiveMediaOnly] is true and + //option will be [FilePickerOptions.FILE] + if (config.useLiveMediaOnly && option == FilePickerOptions.FILE) { + final allowedFileTypes = getAllowedFileBrowserTypes( + useLiveMediaOnly: config.useLiveMediaOnly, + allowedFileTypes: config.allowedExtensions, + ); + if (allowedFileTypes.isNotEmpty && !allowedFileTypes.contains(wrapper.extension)) { + return FilePickerException(PickerExceptionType.unsupportedFile); + } + } + // File type check if (config.allowedExtensions.isNotEmpty && !config.allowedExtensions.contains(wrapper.extension)) { return FilePickerException(PickerExceptionType.unsupportedFile); @@ -76,7 +89,7 @@ Future zdsValidator( // check if the file size is within the limit if (!(wrapper.isImage() || wrapper.isVideo()) && config.maxFileSize > 0 && config.maxFileSize < await file.length()) { - return FilePickerException(PickerExceptionType.maxFileSize, args: [fileSizeWithUnit(config.maxFileSize)]); + return FilePickerException(PickerExceptionType.maxFileSize, args: [fileSizeWithUnit(config.maxFileSize)]); } return null; @@ -106,8 +119,8 @@ void zdsFileError(BuildContext context, FilePickerConfig config, Exception excep ///extension used to return different strings on exceptions. extension TextMessage on PickerExceptionType { /// method returns FilePickerException message's. - String message(BuildContext context, {List args = const []}) { - final strings = ComponentStrings.of(context); + String message(BuildContext context, {List args = const []}) { + final ComponentStrings strings = ComponentStrings.of(context); switch (this) { case PickerExceptionType.unsupportedFile: return strings.get('FILE_UNSUPPORTED', 'This file type is not allowed'); diff --git a/lib/src/components/organisms/file_picker/file_wrapper.dart b/lib/src/components/organisms/file_picker/file_wrapper.dart index ba48304..e19ee48 100644 --- a/lib/src/components/organisms/file_picker/file_wrapper.dart +++ b/lib/src/components/organisms/file_picker/file_wrapper.dart @@ -1,12 +1,10 @@ // ignore_for_file: constant_identifier_names import 'package:flutter/cupertino.dart'; -import 'package:giphy_get/giphy_get.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart' as mime; import 'package:path/path.dart' as path; - -import '../../../../zds_flutter.dart'; +import 'file_picker.dart'; /// Extension on FilePickerException to show message @@ -87,7 +85,7 @@ class FileWrapper { /// Returns mimeType of the [content] if it is a valid file String? get mimeType { if (content is XFile) { - final file = content as XFile; + final XFile file = content as XFile; return file.mimeType ?? mime.lookupMimeType(file.path) ?? mime.lookupMimeType(file.name); } else { return null; @@ -120,12 +118,12 @@ class FileWrapper { // ignore: avoid_dynamic_calls if (other.content.runtimeType != content.runtimeType) return false; if (content is XFile && other.content is XFile) { - final f1 = content as XFile; - final f2 = other.content as XFile; + final XFile f1 = content as XFile; + final XFile f2 = other.content as XFile; return f1.name == f2.name || f1.path == f2.path; } else if (content is XUri && other.content is XUri) { - final u1 = content as XUri; - final u2 = other.content as XUri; + final XUri u1 = content as XUri; + final XUri u2 = other.content as XUri; return u1.uri == u2.uri; } else { return content == other.content; @@ -136,15 +134,15 @@ class FileWrapper { /// Uri wrapper @immutable class XUri { + /// Const constructor + const XUri({required this.uri, required this.name}); + /// Uri final Uri uri; /// Name of the uri final String name; - /// Const constructor - const XUri({required this.uri, required this.name}); - /// Creates a deep copy XUri copyWith({Uri? uri, String? name}) { return XUri(uri: uri ?? this.uri, name: name ?? this.name); diff --git a/lib/src/components/organisms/file_picker/giphy_picker.dart b/lib/src/components/organisms/file_picker/giphy_picker.dart index 139bf4c..cefbb1b 100644 --- a/lib/src/components/organisms/file_picker/giphy_picker.dart +++ b/lib/src/components/organisms/file_picker/giphy_picker.dart @@ -1,22 +1,32 @@ import 'dart:async'; - import 'package:extended_image/extended_image.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:giphy_get/giphy_get.dart'; -import '../../../../zds_flutter.dart'; +import '../../../utils/assets/icons.dart'; +import '../../../utils/localizations/translation.dart'; +import '../../../utils/tools/utils.dart'; +import '../../molecules/empty.dart'; +import '../../molecules/search.dart'; + +/// A widget to pick Giphy images. +/// +/// Displays a collection of Giphy images based on the query provided +/// by the user. The user can select a GIF from the displayed collection. -/// See [ZdsFilePicker]. class ZdsGiphyPicker extends StatefulWidget { + /// Creates a [ZdsGiphyPicker] widget. + /// + /// The [key] parameter is optional and is used to control the framework's + /// widget replacement and state synchronization mechanisms. + const ZdsGiphyPicker({super.key, required this.apiKey}); + /// API Key, required to use giphy service. /// - /// See https://developers.giphy.com/ + /// See [Giphy Developers](https://developers.giphy.com/). final String apiKey; - /// See [ZdsFilePicker]. - const ZdsGiphyPicker({super.key, required this.apiKey}); - @override State createState() => _ZdsGiphyPickerState(); @override @@ -30,26 +40,31 @@ class _ZdsGiphyPickerState extends State { // is Loading gifs bool _isLoading = false; - // Collection + /// Represents a collection of Giphy GIFs. GiphyCollection? _collection; + /// Text for querying GIFs. String _queryText = ''; - // List of gifs - final List _list = []; + /// Contains the list of fetched GIFs. + final List _list = []; - // Limit of query + /// Maximum number of GIFs to query at once. late int _limit; - // Offset + /// The next GIF in the collection to retrieve. int offset = 0; + /// Controller to manage scroll behavior. ScrollController scrollController = ScrollController(); - final TextEditingController _searchController = TextEditingController(); - bool _hasText = false; + /// Controller to manage the search text. + final TextEditingController _searchController = TextEditingController(); + /// Timer used to debounce search queries. Timer? _debounce; + + /// Delay before the debounce effect takes place. late Duration debounceDelay; @override @@ -57,9 +72,7 @@ class _ZdsGiphyPickerState extends State { super.initState(); _searchController.addListener(() { - setState(() { - _hasText = _searchController.text.isNotEmpty; - }); + setState(() {}); }); scrollController.addListener(_loadMore); @@ -71,12 +84,6 @@ class _ZdsGiphyPickerState extends State { const double gifWidth = 80; - _searchController.addListener(() { - setState(() { - _hasText = _searchController.text.isNotEmpty; - }); - }); - scrollController.addListener(_loadMore); // Set items count responsive @@ -102,9 +109,9 @@ class _ZdsGiphyPickerState extends State { @override Widget build(BuildContext context) { - final clearButton = _hasText + final IconButton? clearButton = _searchController.text.isNotEmpty ? IconButton( - icon: Icon(ZdsIcons.close_circle, color: ZdsColors.greySwatch(context)[800]), + icon: const Icon(ZdsIcons.close_circle), onPressed: () { _searchController.clear(); _queryText = ''; @@ -116,69 +123,73 @@ class _ZdsGiphyPickerState extends State { return Scaffold( appBar: AppBar(title: Text(ComponentStrings.of(context).get('PICK_GIF', 'Pick a Gif'))), backgroundColor: Theme.of(context).colorScheme.background, - body: Column( - children: [ - ZdsSearchField( - hintText: ComponentStrings.of(context).get('SEARCH_GIF', 'Search all the GIFs'), - suffixIcon: clearButton, - controller: _searchController, - onChange: (value) { - if (_debounce?.isActive ?? false) _debounce?.cancel(); - _debounce = Timer(const Duration(milliseconds: 500), () async { - setState(() { - _queryText = value; - _listenerQuery(); - }); - }); - }, - ), - if (_isLoading && _list.isEmpty) - const Expanded(child: Center(child: CircularProgressIndicator())) - else if (_list.isNotEmpty) - Expanded( - child: GridView.builder( - itemCount: _list.length, - padding: const EdgeInsets.symmetric(horizontal: 12), - controller: scrollController, - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - crossAxisSpacing: 2, - mainAxisSpacing: 2, - ), - itemBuilder: (ctx, idx) { - return _item(ctx, _list[idx]); + body: LayoutBuilder( + builder: (BuildContext context, BoxConstraints box) { + return Column( + children: [ + ZdsSearchField( + hintText: ComponentStrings.of(context).get('SEARCH_GIF', 'Search all the GIFs'), + suffixIcon: clearButton, + controller: _searchController, + onChange: (String value) { + if (_debounce?.isActive ?? false) _debounce?.cancel(); + _debounce = Timer(const Duration(milliseconds: 500), () async { + setState(() { + _queryText = value; + _listenerQuery(); + }); + }); }, ), - ) - else - const ZdsEmpty(), - ], + if (_isLoading && _list.isEmpty) + const Expanded(child: Center(child: CircularProgressIndicator())) + else if (_list.isNotEmpty) + Expanded( + child: GridView.builder( + itemCount: _list.length, + padding: const EdgeInsets.symmetric(horizontal: 12), + controller: scrollController, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: box.maxWidth > 500 ? 200 : 100, + crossAxisSpacing: 2, + mainAxisSpacing: 2, + ), + itemBuilder: (BuildContext ctx, int idx) => _item(ctx, _list[idx]), + ), + ) + else + const ZdsEmpty(), + ], + ); + }, ), ); } Widget _item(BuildContext context, GiphyGif gif) { + final String? url = gif.images?.previewWebp?.url; return InkWell( onTap: () => Navigator.pop(context, gif), - child: gif.images == null || gif.images?.fixedWidth.webp == null + child: url == null ? Container() : ExtendedImage.network( - gif.images!.fixedWidth.webp!, + url, semanticLabel: gif.title, gaplessPlayback: true, - headers: const {'accept': 'image/*'}, - loadStateChanged: (state) => AnimatedSwitcher( + fit: BoxFit.fill, + headers: const {'accept': 'image/*'}, + loadStateChanged: (ExtendedImageState state) => AnimatedSwitcher( duration: const Duration(milliseconds: 350), child: gif.images == null ? Container() - : { + : { LoadState.loading: AspectRatio( aspectRatio: 1, child: Container(color: Theme.of(context).cardColor), ), LoadState.completed: AspectRatio( aspectRatio: 1, - child: ExtendedRawImage(fit: BoxFit.contain, image: state.extendedImageInfo?.image), + child: ExtendedRawImage(fit: BoxFit.fill, image: state.extendedImageInfo?.image), ), LoadState.failed: AspectRatio( aspectRatio: 1, @@ -186,7 +197,7 @@ class _ZdsGiphyPickerState extends State { ), }.get( state.extendedImageLoadState, - orDefault: AspectRatio( + fallback: AspectRatio( aspectRatio: 1, child: Container( color: Theme.of(context).cardColor, @@ -255,8 +266,9 @@ class _ZdsGiphyPickerState extends State { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IntProperty('offset', offset)); - properties.add(DiagnosticsProperty('scrollController', scrollController)); - properties.add(DiagnosticsProperty('debounceDelay', debounceDelay)); + properties + ..add(DiagnosticsProperty('debounceDelay', debounceDelay)) + ..add(IntProperty('offset', offset)) + ..add(DiagnosticsProperty('scrollController', scrollController)); } } diff --git a/lib/src/components/organisms/file_picker/image_crop.dart b/lib/src/components/organisms/file_picker/image_crop.dart new file mode 100644 index 0000000..3dffb00 --- /dev/null +++ b/lib/src/components/organisms/file_picker/image_crop.dart @@ -0,0 +1,49 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:image_editor_plus/image_editor_plus.dart'; +import 'package:path/path.dart' as path; + +import '../../../../zds_flutter.dart'; +import '../temp_directory/resolver.dart'; + +/// Editors used to edit only image files & to launch other types of files +class ZdsImageCropPostProcessor implements ZdsFilePostProcessor { + ///default constructor + ZdsImageCropPostProcessor(this.buildContext); + + ///Context used for navigations and toasts + final BuildContextProvider buildContext; + + @override + Future process(FilePickerConfig config, FileWrapper file) async { + if (kIsWeb) return file; + + if (file.isImage() && file.content != null) { + // ignore: avoid_dynamic_calls + final originalFile = File(file.content.path as String); + ImageEditor.i18n(ComponentStrings.of(buildContext.call()).getAll()); + final bytes = await Navigator.of(buildContext.call(), rootNavigator: true).push( + ZdsFadePageRouteBuilder( + fullscreenDialog: true, + builder: (context) { + return ImageCropper( + image: originalFile.readAsBytesSync(), + ); + }, + ), + ); + + if (bytes != null) { + final dir = await zdsTempDirectory('edited'); + await originalFile.delete(recursive: true); + final result = File(path.join(dir, path.basename(originalFile.absolute.path))); + await result.writeAsBytes(bytes); + return FileWrapper(file.type, ZdsXFile.fromFile(result)); + } + } + + return file; + } +} diff --git a/lib/src/components/organisms/file_preview.dart b/lib/src/components/organisms/file_preview.dart index 69622ae..a3405d5 100644 --- a/lib/src/components/organisms/file_preview.dart +++ b/lib/src/components/organisms/file_preview.dart @@ -1,11 +1,15 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:giphy_get/giphy_get.dart'; import 'package:image_picker/image_picker.dart'; import 'package:path/path.dart' as path; +import 'package:zeta_flutter/zeta_flutter.dart'; -import '../../../zds_flutter.dart'; +import '../../utils/assets/icons.dart'; +import '../../utils/localizations/translation.dart'; +import '../../utils/tools/utils.dart'; +import '../atoms/card.dart'; import '../atoms/ximage.dart'; +import 'file_picker/file_picker.dart'; /// Creates a preview of a file. /// @@ -56,7 +60,7 @@ class ZdsFilePreview extends StatelessWidget { Widget build(BuildContext context) { return Stack( clipBehavior: Clip.none, - children: [ + children: [ SizedBox( height: size, width: size, @@ -78,8 +82,8 @@ class ZdsFilePreview extends StatelessWidget { ), if (onDelete != null) Positioned( - top: -12, - right: -12, + top: -15, + right: -15, child: SizedBox( height: 46, width: 44, @@ -88,7 +92,7 @@ class ZdsFilePreview extends StatelessWidget { padding: EdgeInsets.zero, splashRadius: 24, visualDensity: VisualDensity.compact, - icon: Icon(ZdsIcons.close_circle, size: 24, color: ZdsColors.greySwatch(context)[900]), + icon: Icon(ZdsIcons.close_circle, size: 24, color: Zeta.of(context).colors.error), onPressed: onDelete, ), ), @@ -100,7 +104,7 @@ class ZdsFilePreview extends StatelessWidget { Widget _getPreview(double size) { return file.content is GiphyGif // ignore: avoid_dynamic_calls - ? _getImage(Uri.parse(file.content.images.previewGif?.url as String), size) + ? _getImage(Uri.parse(file.content.images!.previewGif.url as String), size) : file.isImage() ? _getImage(file.content, size) : _getFile(file); @@ -116,24 +120,25 @@ class ZdsFilePreview extends StatelessWidget { Widget _getFile(FileWrapper file) { return Builder( - builder: (context) { - final isUrl = file.type == FilePickerOptions.LINK; + builder: (BuildContext context) { + final bool isUrl = file.type == FilePickerOptions.LINK; + final themeData = Theme.of(context); return Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, - children: [ + children: [ Icon( isUrl ? ZdsIcons.sphere : file.name?.fileIcon(), size: 18, - color: Theme.of(context).colorScheme.secondary, + color: themeData.colorScheme.secondary, ), - if (size >= 80) ...[ + if (size >= 80) ...[ const SizedBox(height: 4), Text( isUrl ? file.name ?? '' : (path.extension(file.name ?? 'file.file').replaceAll('.', '')), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Theme.of(context).colorScheme.secondary), + style: themeData.textTheme.bodyMedium?.copyWith(color: themeData.colorScheme.secondary), ), ], ], @@ -145,11 +150,12 @@ class ZdsFilePreview extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('file', file)); - properties.add(DoubleProperty('size', size)); - properties.add(DiagnosticsProperty('useCard', useCard)); - properties.add(ObjectFlagProperty.has('onDelete', onDelete)); - properties.add(ObjectFlagProperty.has('onTap', onTap)); + properties + ..add(DiagnosticsProperty('file', file)) + ..add(DoubleProperty('size', size)) + ..add(DiagnosticsProperty('useCard', useCard)) + ..add(ObjectFlagProperty.has('onDelete', onDelete)) + ..add(ObjectFlagProperty.has('onTap', onTap)); } } @@ -168,7 +174,10 @@ class ZdsFileSize extends StatelessWidget { final int? fileSize; Widget _sizeText(BuildContext context, int size) { - return Text(fileSizeWithUnit(size), style: Theme.of(context).textTheme.bodySmall); + return Text( + fileSizeWithUnit(size), + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Zeta.of(context).colors.textDisabled), + ); } @override @@ -177,7 +186,7 @@ class ZdsFileSize extends StatelessWidget { return FutureBuilder( // ignore: discarded_futures future: file!.length(), - builder: (context, snapshot) { + builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.data != null) { return _sizeText(context, snapshot.data ?? 0); } else { @@ -193,7 +202,8 @@ class ZdsFileSize extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('file', file)); - properties.add(IntProperty('fileSize', fileSize)); + properties + ..add(DiagnosticsProperty('file', file)) + ..add(IntProperty('fileSize', fileSize)); } } diff --git a/lib/src/components/organisms/fiscal_date_picker.dart b/lib/src/components/organisms/fiscal_date_picker.dart new file mode 100644 index 0000000..942f881 --- /dev/null +++ b/lib/src/components/organisms/fiscal_date_picker.dart @@ -0,0 +1,255 @@ +import 'dart:math' as math; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../utils/tools/modifiers.dart'; +import '../../utils/tools/utils.dart'; +import '../atoms/button.dart'; +import 'calendar.dart'; + +const Size _inputPortraitDialogSize = Size(330, 530); +const Size _inputRangeLandscapeDialogSize = Size(500, 480); +const Duration _dialogSizeAnimationDuration = Duration(milliseconds: 200); + +/// Shows a material design date picker dialog. +Future showZdsFiscalDatePicker({ + required BuildContext context, + required DateTime firstDate, + required DateTime lastDate, + required String cancelText, + required String okText, + required String titleText, + Key? key, + RouteSettings? routeSettings, + TransitionBuilder? builder, + DateTime? initialDate, + int startDayOfWeek = 1, + bool useRootNavigator = true, + String format = 'dd/MM/yyyy', +}) { + final Widget dialog = ZdsDatePickerDialog( + firstDate: firstDate, + lastDate: lastDate, + cancelText: cancelText, + okText: okText, + initialDate: initialDate, + helpText: titleText, + startDayOfWeek: startDayOfWeek, + selectedDateFormat: format, + ); + + return showDialog( + context: context, + useRootNavigator: useRootNavigator, + routeSettings: routeSettings, + useSafeArea: false, + builder: (BuildContext context) { + return builder == null ? dialog : builder(context, dialog); + }, + ); +} + +/// A copy of material design date picker dialog with choice of first day of week. +class ZdsDatePickerDialog extends StatefulWidget { + /// Creates a date picker dialog. + const ZdsDatePickerDialog({ + required this.firstDate, + required this.lastDate, + required this.cancelText, + required this.okText, + super.key, + this.selectedDateFormat = 'dd/MM/yyyy', + this.initialDate, + this.helpText, + this.onDateChanged, + this.startDayOfWeek = 1, + }); + + /// The date that is initially selected when the dialog is shown. + final String selectedDateFormat; + + /// Called when the user picks a day. + final void Function(DateTime? dateTime)? onDateChanged; + + /// Starting day of week 1, 2, 3, Sunday, Monday, Tuesday respectively. + final int startDayOfWeek; + + /// The initially selected [DateTime] that the picker should display. + final DateTime? initialDate; + + /// The earliest allowable [DateTime] that the user can select. + final DateTime firstDate; + + /// The latest allowable [DateTime] that the user can select. + final DateTime lastDate; + + /// The text that is displayed on the cancel button. + final String cancelText; + + /// The text that is displayed on the Ok button. + final String okText; + + /// The text that is displayed at the top of the header. + /// + /// This is used to indicate to the user what they are selecting a date for. + final String? helpText; + + @override + State createState() => _ZdsDatePickerDialogState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(StringProperty('helpText', helpText)) + ..add(StringProperty('selectedDateFormat', selectedDateFormat)) + ..add(ObjectFlagProperty.has('onDateChanged', onDateChanged)) + ..add(IntProperty('startDayOfWeek', startDayOfWeek)) + ..add(DiagnosticsProperty('initialDate', initialDate)) + ..add(DiagnosticsProperty('firstDate', firstDate)) + ..add(DiagnosticsProperty('lastDate', lastDate)) + ..add(StringProperty('cancelText', cancelText)) + ..add(StringProperty('okText', okText)); + } +} + +class _ZdsDatePickerDialogState extends State { + DateTime _selectedDate = DateTime.now(); + + @override + void initState() { + _selectedDate = widget.initialDate ?? DateTime.now(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + final Orientation orientation = MediaQuery.of(context).orientation; + final Size size = orientation == Orientation.portrait ? _inputPortraitDialogSize : _inputRangeLandscapeDialogSize; + final double textScaleFactor = math.min(MediaQuery.of(context).textScaleFactor, 1.3); + final theme = Theme.of(context); + + final fixContent = [ + Material( + color: theme.colorScheme.primary, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.all(orientation == Orientation.portrait ? 16 : 16), + child: Text( + widget.helpText ?? 'Select Date', + style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.white), + textAlign: TextAlign.start, + ), + ), + Padding( + padding: EdgeInsets.all(orientation == Orientation.portrait ? 16 : 16), + child: Text( + _selectedDate.format(widget.selectedDateFormat), + style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: Colors.white), + textAlign: TextAlign.start, + ), + ), + ], + ).paddingInsets(const EdgeInsets.symmetric(horizontal: 12)), + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ZdsCalendar.monthly( + initialSelectedDay: _selectedDate, + initialSelectedWeek: _selectedDate, + calendarRowHeight: orientation == Orientation.portrait ? 44 : 38, + headerPadding: EdgeInsets.zero, + calendarHeaderIconColor: Zeta.of(context).colors.iconDefault, + calendarHeaderTextColor: Zeta.of(context).colors.textSubtle, + startingDayOfWeek: _getStartingDayOfWeek(widget.startDayOfWeek), + onDaySelected: (selectedDay, focusedDay) { + setState(() { + _selectedDate = selectedDay; + }); + widget.onDateChanged?.call(selectedDay); + }, + events: const [], + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ZdsButton.text( + child: Text(widget.cancelText), + onTap: () { + Navigator.of(context).pop(); + }, + ), + ZdsButton.text( + child: Text(widget.okText), + onTap: () { + Navigator.pop(context, _selectedDate); + }, + ), + ], + ), + ], + ).paddingInsets(EdgeInsets.symmetric(horizontal: 12, vertical: (orientation == Orientation.portrait ? 8 : 0))), + ), + ]; + + final content = orientation == Orientation.portrait + ? Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: fixContent, + ) + : Row( + children: fixContent, + ); + + return Dialog( + insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), + shape: Theme.of(context).dialogTheme.shape, + elevation: Theme.of(context).dialogTheme.elevation ?? 24, + clipBehavior: Clip.antiAlias, + child: AnimatedContainer( + width: size.width, + height: size.longestSide, + duration: _dialogSizeAnimationDuration, + curve: Curves.easeIn, + child: MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaleFactor: textScaleFactor, + ), + child: Builder( + builder: (BuildContext context) { + return content; + }, + ), + ), + ), + ); + } + + StartingDayOfWeek _getStartingDayOfWeek(int startDayOfWeek) { + StartingDayOfWeek startingDayOfWeek = StartingDayOfWeek.sunday; + switch (startDayOfWeek) { + case 1: + startingDayOfWeek = StartingDayOfWeek.sunday; + case 2: + startingDayOfWeek = StartingDayOfWeek.monday; + case 3: + startingDayOfWeek = StartingDayOfWeek.tuesday; + case 4: + startingDayOfWeek = StartingDayOfWeek.wednesday; + case 5: + startingDayOfWeek = StartingDayOfWeek.thursday; + case 6: + startingDayOfWeek = StartingDayOfWeek.friday; + case 7: + startingDayOfWeek = StartingDayOfWeek.saturday; + } + return startingDayOfWeek; + } +} diff --git a/lib/src/components/organisms/html_preview/html_body.dart b/lib/src/components/organisms/html_preview/html_body.dart new file mode 100644 index 0000000..ec7594b --- /dev/null +++ b/lib/src/components/organisms/html_preview/html_body.dart @@ -0,0 +1,284 @@ +import 'dart:async'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:csslib/parser.dart' hide Border, LineHeight; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_html_audio/flutter_html_audio.dart'; +import 'package:flutter_html_svg/flutter_html_svg.dart'; +import 'package:html/dom.dart' as html; +import '../../../../zds_flutter.dart'; +import 'nested_table.dart'; +import 'table_html_extension.dart'; +import 'video_html_extension.dart'; + +export 'package:html/dom.dart' show Element; + +/// A widget for displaying HTML content using a WebView. +/// +/// This widget takes HTML content as input and displays it in a styled format +/// using the Flutter HTML package. It supports features such as setting the +/// font size, limiting the number of displayed lines, and handling links. +class ZdsHtml extends StatelessWidget { + /// Creates a new instance of the [ZdsHtml] widget. + /// + /// The [htmlText] parameter is required, and other parameters are optional. + const ZdsHtml( + this.htmlText, { + super.key, + this.fontSize, + this.maxLines = 999, + this.onLinkTap, + this.extensions = const {}, + this.style = const {}, + }); + + /// The HTML content to be displayed. + final String htmlText; + + /// The maximum number of lines to display. Defaults to 5. + final int maxLines; + + /// The font size for the HTML content. If null, the default font size is used. + final double? fontSize; + + /// A Map of [HtmlExtension]s that add additional capabilities to flutter_html + /// See the [HtmlExtension] class for more details. + final Map extensions; + + /// An API that allows you to override the default style for any HTML element + final Map style; + + /// A callback function that is called when a link is tapped within the HTML content. + /// + /// The callback receives the URL of the tapped link, a map of attributes + /// associated with the link, and the HTML element containing the link. + final void Function(String? url, Map attributes, html.Element? element)? onLinkTap; + + @override + Widget build(BuildContext context) { + final themeData = Theme.of(context); + final colorscheme = themeData.colorScheme; + BoxDecoration boxDecoration() => BoxDecoration( + color: Zeta.of(context).colors.surfaceDisabled, + border: Border.all(color: Zeta.of(context).colors.borderSubtle, width: 0.5), + borderRadius: BorderRadius.circular(8), + ); + + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints box) { + return Html( + data: htmlText, + style: { + 'p': Style( + fontSize: fontSize != null ? FontSize(fontSize!) : null, + maxLines: maxLines, + lineHeight: LineHeight.percent(125), + textOverflow: TextOverflow.ellipsis, + margin: Margins.only(left: 0, right: 0), + ), + 'li': Style( + fontSize: fontSize != null ? FontSize(fontSize!) : null, + maxLines: maxLines, + lineHeight: LineHeight.percent(125), + textOverflow: TextOverflow.ellipsis, + margin: Margins.only(left: 0, right: 0), + backgroundColor: Theme.of(context).colorScheme.surface, + ), + 'table': Style( + width: Width.auto(), + border: Border( + bottom: BorderSide(color: colorscheme.onBackground), + left: BorderSide(color: colorscheme.onBackground), + right: BorderSide(color: colorscheme.onBackground), + top: BorderSide(color: colorscheme.onBackground), + ), + ), + 'tr': Style( + width: Width.auto(), + border: Border( + bottom: BorderSide(color: colorscheme.onBackground, width: 0.5), + left: BorderSide(color: colorscheme.onBackground, width: 0.5), + right: BorderSide(color: colorscheme.onBackground, width: 0.5), + top: BorderSide(color: colorscheme.onBackground, width: 0.5), + ), + ), + 'th': Style(width: Width.auto(), padding: HtmlPaddings.all(6)), + 'td': Style( + width: Width.auto(), + padding: HtmlPaddings.all(6), + alignment: Alignment.topLeft, + border: Border( + bottom: BorderSide(color: colorscheme.onBackground, width: 0.5), + left: BorderSide(color: colorscheme.onBackground, width: 0.5), + right: BorderSide(color: colorscheme.onBackground, width: 0.5), + top: BorderSide(color: colorscheme.onBackground, width: 0.5), + ), + ), + 'h5': Style(maxLines: maxLines, textOverflow: TextOverflow.ellipsis), + 'iframe': Style(width: Width(box.maxWidth), height: Height((box.maxWidth / 16) * 9)), + 'figure': Style(width: Width(box.maxWidth)), + 'blockquote': Style( + padding: HtmlPaddings.only(left: 16), + border: Border(left: BorderSide(color: Zeta.of(context).colors.borderSubtle, width: 5)), + ), + ...style, + }, + extensions: [ + TagWrapExtension( + tagsToWrap: {'table'}, + builder: (Widget child) { + return SingleChildScrollView( + padding: const EdgeInsets.only(right: 150), + scrollDirection: Axis.horizontal, + physics: const ClampingScrollPhysics(), + child: child, + ); + }, + ), + const ZdsTableHtmlExtension(), + extensions.get( + 'video', + fallback: const ZdsVideoHtmlExtension(), + ), + extensions.get( + 'audio', + fallback: const AudioHtmlExtension(), + ), + extensions.get( + 'svg', + fallback: const SvgHtmlExtension(), + ), + extensions.get( + 'img', + fallback: TagExtension( + tagsToExtend: {'img'}, + builder: (ctx) { + final url = ctx.attributes['src']; + return url != null && url.isNotEmpty + ? ConstrainedBox( + constraints: BoxConstraints(maxWidth: box.maxWidth), + child: kIsWeb ? Image.network(url) : CachedNetworkImage(imageUrl: url), + ) + : Container(); + }, + ), + ), + extensions.get( + 'loader', + fallback: TagExtension( + tagsToExtend: {'loader'}, + builder: (ctx) { + return DecoratedBox( + decoration: boxDecoration(), + child: const AspectRatio( + aspectRatio: 16 / 9, + child: Center(child: SizedBox(height: 24, width: 24, child: CircularProgressIndicator())), + ), + ); + }, + ), + ), + extensions.get( + 'nestedtable', + fallback: TagExtension( + tagsToExtend: {'nestedtable'}, + builder: (ctx) { + return InkWell( + child: Text( + ComponentStrings.of(context).get('TABLE_CONTENT', 'Click to see table content'), + style: const TextStyle(color: Colors.blue, decoration: TextDecoration.underline), + ), + onTap: () { + final tableHtml = ctx.element?.outerHtml; + final applycss = (ctx.element?.attributes ?? {})['applycss'] == 'true'; + if (tableHtml != null && tableHtml.isNotEmpty) { + unawaited( + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => ZdsNestedTableView(tableHtml, applyCss: applycss)), + ), + ); + } + }, + ).paddingOnly(top: 10, bottom: 10); + }, + ), + ), + extensions.get( + 'mediacontainer', + fallback: TagExtension( + tagsToExtend: {'mediacontainer'}, + builder: (ctx) { + final url = ctx.attributes['src']; + final zetaColors = Zeta.of(context).colors; + return url != null && url.isNotEmpty + ? InkWell( + child: DecoratedBox( + decoration: boxDecoration(), + child: AspectRatio( + aspectRatio: 16 / 9, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.error, + color: zetaColors.iconSubtle, + size: 50, + ).paddingOnly(bottom: 20), + Text( + ComponentStrings.of(context).get('MEDIA_ERROR', 'Error loading media.'), + style: themeData.textTheme.headlineMedium, + ).paddingOnly(bottom: 10), + Text( + url, + style: themeData.textTheme.bodyMedium + ?.copyWith(color: zetaColors.link, decoration: TextDecoration.underline), + textAlign: TextAlign.center, + ), + ], + ), + ), + ).padding(10), + ), + onTap: () { + onLinkTap?.call(url, ctx.attributes, ctx.element); + }, + ) + : const SizedBox.shrink(); + }, + ), + ), + ], + onLinkTap: onLinkTap, + onCssParseError: (String css, List messages) { + debugPrint('css that errored: $css'); + debugPrint('error messages:'); + for (final Message element in messages) { + debugPrint(element.toString()); + } + return ''; + }, + ); + }, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(StringProperty('htmlText', htmlText)) + ..add(IntProperty('maxLines', maxLines)) + ..add(DoubleProperty('fontSize', fontSize)) + ..add( + ObjectFlagProperty attributes, html.Element? element)?>.has( + 'onLinkTap', + onLinkTap, + ), + ) + ..add(DiagnosticsProperty>('extensions', extensions)) + ..add(DiagnosticsProperty>('style', style)); + } +} diff --git a/lib/src/components/organisms/html_preview/html_container.dart b/lib/src/components/organisms/html_preview/html_container.dart new file mode 100644 index 0000000..5e1e2c8 --- /dev/null +++ b/lib/src/components/organisms/html_preview/html_container.dart @@ -0,0 +1,343 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:html/dom.dart' as dom; +import 'package:html/parser.dart' show parse; +import 'package:http_client_helper/http_client_helper.dart'; +import '../../../../../zds_flutter.dart'; +import 'html_body.dart' as html; + +/// An enumeration to represent different types of media content. +enum MediaType { + /// audio media + audio, + + /// video media + video, + + /// webUrl + webUrl +} + +/// A container widget for displaying HTML content with optional features. +/// +/// This widget can display HTML content with options for text expansion, setting +/// font size, displaying a "Read More" link, and handling links. It also transforms +/// media tags to audio/video tags and iframe tags to href links. +class ZdsHtmlContainer extends StatefulWidget { + /// Creates a new instance of the [ZdsHtmlContainer] widget. + /// + /// The [htmlText] parameter is required, and other parameters are optional. + const ZdsHtmlContainer( + this.htmlText, { + super.key, + this.expanded = false, + this.fontSize, + this.showReadMore = true, + this.onLinkTap, + this.containerHeight = 200, + this.extensions = const {}, + this.style = const {}, + }); + + /// The HTML content to be displayed. + final String htmlText; + + /// Determines whether the text is initially expanded. Defaults to `false`. + final bool expanded; + + /// The font size for the HTML content. If null, the default font size is used. + final double? fontSize; + + /// Controls the visibility of the "Read More" link. Defaults to `true`. + final bool showReadMore; + + ///Height of Html Container + final double containerHeight; + + /// Add custom extensions to override the existing ones + /// Following can be overridden tableTagWrap, tableHtml, video, audio, svg, img, loader, nestedTable, mediaContainer + final Map extensions; + + /// An API that allows you to override the default style for any HTML element + final Map style; + + /// A callback function that is called when a link is tapped within the HTML content. + /// + /// The callback receives the URL of the tapped link, a map of attributes + /// associated with the link, and the HTML element containing the link. + final void Function(String? url, Map attributes, html.Element? element)? onLinkTap; + + @override + State createState() => _ZdsHtmlContainerState(); + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add( + ObjectFlagProperty attributes, html.Element? element)?>.has( + 'onLinkTap', + onLinkTap, + ), + ) + ..add(StringProperty('htmlText', htmlText)) + ..add(DiagnosticsProperty('expanded', expanded)) + ..add(DoubleProperty('fontSize', fontSize)) + ..add(DiagnosticsProperty('showReadMore', showReadMore)) + ..add(DoubleProperty('containerHeight', containerHeight)) + ..add(DiagnosticsProperty>('extensions', extensions)) + ..add(DiagnosticsProperty>('style', style)); + } +} + +class _ZdsHtmlContainerState extends State with FrameCallbackMixin { + bool expanded = false; + bool hasMore = false; + String htmlContent = ''; + double? containerWidth; + + Map embeddedMedia = {}; + + static final mediaRegex = RegExp('
.*?data-oembed-url="(.*?)".*?
', dotAll: true); + static final loaderRegex = RegExp(r'', dotAll: true); + static final iFrameRegex = RegExp('', dotAll: true); + static final nestedTableRegex = RegExp('.*?.*?.*?', dotAll: true); + + static const _maxLines = 2; + + @override + void initState() { + _initialize(); + super.initState(); + } + + void _initialize() { + expanded = widget.expanded || !widget.showReadMore; + htmlContent = widget.htmlText; + _transformWebView(); + } + + void _setContainerWidth(double width) { + containerWidth = width; + if (widget.showReadMore) { + _updateHasMore(); + } + } + + void _updateHasMore() { + final TextPainter tp = TextPainter( + maxLines: _maxLines, + textDirection: TextDirection.ltr, + text: TextSpan( + text: widget.htmlText, + style: TextStyle(fontSize: widget.fontSize), + ), + )..layout( + maxWidth: containerWidth ?? MediaQuery.of(context).size.width, + ); + + if (hasMore != tp.didExceedMaxLines) { + setState(() { + hasMore = tp.didExceedMaxLines; + }); + } + } + + void _transformWebView() { + try { + _handleNestedTable(); + _addMediaLoaders(); + unawaited( + _collectMediaUrls().then((_) { + _transformMediaFigures(); + _refreshUI(); + }), + ); + _transformIFrameTag(); + } finally { + _refreshUI(); + } + } + + void _refreshUI() { + if (mounted) { + setState(() {}); + } + } + + Future _collectMediaUrls() async { + final Iterable matches = loaderRegex.allMatches(htmlContent); + for (final RegExpMatch match in matches) { + final String? mediaUrl = match.group(1); + if (mediaUrl != null) { + final MediaType mediaType = await _getMediaType(mediaUrl); + embeddedMedia[mediaUrl] = mediaType; + } + } + } + + void _addMediaLoaders() { + String mediaUrl; + htmlContent = htmlContent.replaceAllMapped(mediaRegex, (Match match) { + mediaUrl = match.group(1) ?? ''; + return ''; + }); + } + + void _handleNestedTable() { + final document = parse(htmlContent); + final tables = document.getElementsByTagName('table'); + for (final table in tables) { + if (nestedTableRegex.hasMatch(table.outerHtml)) { + final nesTable = dom.Element.tag('nestedtable'); + table.replaceWith(nesTable); + nesTable.append(table); + if (table.attributes['border'] == null || (table.attributes['border']?.isEmpty ?? true)) { + nesTable.attributes.addAll({'applyCss': 'true'}); + } + final div = dom.Element.tag('div'); + nesTable.replaceWith(div); + div.append(nesTable); + } + } + htmlContent = document.outerHtml; + } + + void _transformMediaFigures() { + String mediaUrl; + htmlContent = htmlContent.replaceAllMapped(loaderRegex, (Match match) { + mediaUrl = match.group(1) ?? ''; + String attributes = 'controls'; + if (containerWidth != null) { + attributes = '$attributes width=$containerWidth height=${(containerWidth! / 16) * 9}'; + } + final MediaType? mediaType = embeddedMedia[mediaUrl]; + if (mediaType == MediaType.audio || mediaType == MediaType.video) { + return '

'; + } else { + return '

'; + } + }); + } + + void _transformIFrameTag() { + htmlContent = htmlContent.replaceAllMapped(iFrameRegex, (Match match) { + final String url = match.group(1) ?? ''; + return '

$url

'; + }); + } + + Future _getMediaType(String url) async { + MediaType type = MediaType.webUrl; + try { + final Response? response = await HttpClientHelper.head(Uri.parse(url), retries: 2); + if (response != null) { + final String? contentType = response.headers['content-type']; + if (contentType != null && contentType.isNotEmpty) { + type = contentType.startsWith('audio/') + ? MediaType.audio + : contentType.startsWith('video/') + ? MediaType.video + : MediaType.webUrl; + } + } + } catch (e) { + type = MediaType.webUrl; + } + return type; + } + + @override + Widget build(BuildContext context) { + final ColorScheme surfaceColor = Theme.of(context).colorScheme; + final html.ZdsHtml htmlView = html.ZdsHtml( + htmlContent, + fontSize: widget.fontSize, + onLinkTap: widget.onLinkTap, + extensions: widget.extensions, + style: widget.style, + ); + + return LayoutBuilder( + builder: (ctx, box) { + if (widget.showReadMore) atLast(() => _setContainerWidth(box.maxWidth)); + return widget.showReadMore + ? Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + children: [ + Container( + decoration: const BoxDecoration(), + constraints: BoxConstraints(maxHeight: expanded ? double.infinity : widget.containerHeight), + clipBehavior: Clip.hardEdge, + child: htmlView.paddingOnly(bottom: (hasMore && expanded) ? 24 : 0), + ), + if (hasMore && !expanded) + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + height: 40, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + surfaceColor.surface.withOpacity(0.3), + surfaceColor.surface.withOpacity(0.4), + surfaceColor.surface.withOpacity(0.5), + surfaceColor.surface.withOpacity(0.6), + surfaceColor.surface.withOpacity(0.7), + surfaceColor.surface.withOpacity(0.8), + surfaceColor.surface.withOpacity(0.9), + surfaceColor.surface, + ], + ), + ), + ), + ), + ], + ), + if (hasMore) + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + InkWell( + onTap: () => setState(() => expanded = !expanded), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: Text( + expanded + ? ComponentStrings.of(context).get('READ_LESS', 'Read Less') + : ComponentStrings.of(context).get('READ_MORE', 'Read More'), + style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: surfaceColor.secondary), + ), + ), + ), + ], + ), + ], + ) + : htmlView; + }, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('expanded', expanded)) + ..add(DiagnosticsProperty('hasMore', hasMore)) + ..add(StringProperty('htmlContent', htmlContent)) + ..add(DiagnosticsProperty>('embeddedMedia', embeddedMedia)) + ..add(DiagnosticsProperty('mediaRegex', mediaRegex)) + ..add(DiagnosticsProperty('iFrameRegex', iFrameRegex)) + ..add(DoubleProperty('containerWidth', containerWidth)); + } +} diff --git a/lib/src/components/organisms/html_preview/nested_table.dart b/lib/src/components/organisms/html_preview/nested_table.dart new file mode 100644 index 0000000..d5d72b6 --- /dev/null +++ b/lib/src/components/organisms/html_preview/nested_table.dart @@ -0,0 +1,91 @@ +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; + +/// It applied viewport script for page meta-data +class ZdsNestedTableView extends StatelessWidget { + /// Creates a new instance of the [ZdsNestedTableView] widget. + /// + /// The [html] parameter is required. + const ZdsNestedTableView(this.html, {super.key, this.applyCss = false}); + + /// The HTML content to be displayed. + final String html; + + /// Apply css if true + final bool applyCss; + + /// It applied viewport script for page meta-data + String get _viewportScript => ''' + var meta = document.createElement('meta'); + meta.setAttribute('name', 'viewport'); + meta.setAttribute('content', 'width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no, viewport-fit=cover'); + document.getElementsByTagName('head')[0].appendChild(meta); + '''; + + ////Table Style + String get _tablecss => + 'table, th, td{border:1px solid gray;}table {border-collapse: collapse;}td, tr{padding:6px}th {text-align: left;}'; + + ///Initial `data` as a content for an [WebView] instance. + InAppWebViewInitialData? get initialData => InAppWebViewInitialData( + data: html, + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: SafeArea( + child: InAppWebView( + initialData: initialData, + initialUserScripts: UnmodifiableListView([ + UserScript(source: _viewportScript, injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END), + ]), + gestureRecognizers: const { + Factory(VerticalDragGestureRecognizer.new), + Factory(HorizontalDragGestureRecognizer.new), + }, + initialOptions: InAppWebViewGroupOptions( + crossPlatform: InAppWebViewOptions( + useShouldOverrideUrlLoading: true, + mediaPlaybackRequiresUserGesture: false, + ), + android: AndroidInAppWebViewOptions( + useHybridComposition: true, + ), + ios: IOSInAppWebViewOptions( + allowsInlineMediaPlayback: true, + ), + ), + onPageCommitVisible: (controller, url) { + if (applyCss) { + unawaited( + controller.evaluateJavascript( + source: """ + var style = document.createElement('style'); + style.innerHTML = "$_tablecss"; + document.head.appendChild(style); + """, + ), + ); + } + }, + ), + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(StringProperty('html', html)) + ..add(DiagnosticsProperty('initialData', initialData)) + ..add(DiagnosticsProperty('applyCss', applyCss)); + } +} diff --git a/lib/src/components/organisms/html_preview/table_html_extension.dart b/lib/src/components/organisms/html_preview/table_html_extension.dart new file mode 100644 index 0000000..b295396 --- /dev/null +++ b/lib/src/components/organisms/html_preview/table_html_extension.dart @@ -0,0 +1,450 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_html_table/flutter_html_table.dart'; +import 'package:flutter_layout_grid/flutter_layout_grid.dart'; +import 'package:html/dom.dart' as html; + +/// [TableHtmlExtension] adds support for the element to the flutter_html library. +/// , , , , , and are also +/// supported. +/// +/// Currently, nested tables are not supported. +class ZdsTableHtmlExtension extends HtmlExtension { + /// Creates a new instance of the [ZdsTableHtmlExtension] widget. + const ZdsTableHtmlExtension(); + + @override + Set get supportedTags => { + 'table', + 'tr', + 'tbody', + 'tfoot', + 'thead', + 'th', + 'td', + 'col', + 'p', + 'div', + 'blockquote', + 'ol', + 'ul', + 'li', + 'colgroup', + }; + + @override + bool matches(ExtensionContext context) { + final String tag = context.elementName; + return supportedTags.contains(tag) && (tag == 'table' || isTableParent(context.node)); + } + + //// Check if node has Table as ParentNode + bool isTableParent(html.Node? node) { + final String name = node?.parentNode?.elementName ?? ''; + if (name == 'table') { + return true; + } else if (node?.parentNode != null) { + return isTableParent(node?.parentNode); + } else { + return false; + } + } + + @override + StyledElement prepare( + ExtensionContext context, + List children, + ) { + if (context.elementName == 'table') { + final List cellDescendants = _getCellDescendants(children); + return TableElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + tableStructure: children, + cellDescendants: cellDescendants, + style: Style(display: Display.block), + node: context.node, + ); + } + + if (context.elementName == 'th' || context.elementName == 'td') { + return TableCellElement( + style: context.elementName == 'th' + ? Style( + fontWeight: FontWeight.bold, + textAlign: TextAlign.center, + verticalAlign: VerticalAlign.middle, + ) + : Style( + verticalAlign: VerticalAlign.middle, + ), + children: children, + node: context.node, + name: context.elementName, + elementClasses: context.classes.toList(), + elementId: context.id, + ); + } + + if (context.elementName == 'tbody' || context.elementName == 'thead' || context.elementName == 'tfoot') { + return TableSectionLayoutElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style(), + node: context.node, + ); + } + + if (context.elementName == 'tr') { + return TableRowLayoutElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style(), + node: context.node, + ); + } + + if (context.elementName == 'col' || context.elementName == 'colgroup') { + return TableStyleElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style(), + node: context.node, + ); + } else if (context.elementName == 'p' || context.elementName == 'li') { + return TableStyleElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style(after: '\n'), + node: context.node, + ); + } else if (context.elementName == 'blockquote') { + return StyledElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style( + textAlign: TextAlign.end, + verticalAlign: VerticalAlign.middle, + margin: Margins.symmetric(horizontal: 40, vertical: 14), + display: Display.block, + ), + node: context.node, + ); + } else if (context.elementName == 'li') { + return TableCellElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style( + display: Display.listItem, + ), + node: context.node, + ); + } else if (context.elementName == 'ol') { + return TableStyleElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style( + display: Display.block, + listStyleType: ListStyleType.decimal, + padding: HtmlPaddings.only(inlineStart: 40), + margin: Margins( + blockStart: Margin(1, Unit.em), + blockEnd: Margin(1, Unit.em), + ), + ), + node: context.node, + ); + } else if (context.elementName == 'ul') { + return TableStyleElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style( + display: Display.block, + listStyleType: ListStyleType.disc, + padding: HtmlPaddings.only(inlineStart: 40), + margin: Margins( + blockStart: Margin(1, Unit.em), + blockEnd: Margin(1, Unit.em), + ), + ), + node: context.node, + ); + } else if (context.elementName == 'div') { + return TableStyleElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + children: children, + style: Style( + display: Display.block, + ), + node: context.node, + ); + } + + return StyledElement( + name: context.elementName, + elementId: context.id, + elementClasses: context.classes.toList(), + node: context.node, + children: children, + style: Style(), + ); + } + + @override + InlineSpan build(ExtensionContext context) { + if (context.elementName == 'table') { + return WidgetSpan( + child: CssBoxWidget( + style: context.styledElement!.style, + shrinkWrap: true, + child: LayoutBuilder( + builder: (_, BoxConstraints constraints) { + if (context.styledElement != null && context.styledElement is TableElement) { + return _layoutCells( + context.styledElement! as TableElement, + context.builtChildrenMap!, + context, + constraints, + ); + } + return const SizedBox(); + }, + ), + ), + ); + } + + return WidgetSpan( + child: CssBoxWidget.withInlineSpanChildren( + children: context.inlineSpanChildren!, + style: Style(), + ), + ); + } +} + +/// Recursively gets a flattened list of the table's +/// cell descendants +List _getCellDescendants(List children) { + final List descendants = []; + + for (final StyledElement child in children) { + if (child is TableCellElement) { + descendants.add(child); + } + + descendants.addAll(_getCellDescendants(child.children)); + } + + return descendants; +} + +Widget _layoutCells( + TableElement table, + Map parsedCells, + ExtensionContext context, + BoxConstraints constraints, +) { + final List rows = []; + List columnSizes = []; + for (final StyledElement child in table.tableStructure) { + if (child is TableStyleElement) { + // Map tags to predetermined column track sizes + columnSizes = child.children + .where((StyledElement c) => c.name == 'col') + .map((StyledElement c) { + final int span = int.tryParse(c.attributes['span'] ?? '1') ?? 1; + final String? colWidth = c.attributes['width']; + return List.generate(span, (int index) { + if (colWidth != null && colWidth.endsWith('%')) { + if (!constraints.hasBoundedWidth) { + // In a horizontally unbounded container; always wrap content instead of applying flex + return const IntrinsicContentTrackSize(); + } + final double? percentageSize = double.tryParse(colWidth.substring(0, colWidth.length - 1)); + return percentageSize != null && !percentageSize.isNaN + ? FlexibleTrackSize(percentageSize / 100) + : const IntrinsicContentTrackSize(); + } else if (colWidth != null) { + final double? fixedPxSize = double.tryParse(colWidth); + return fixedPxSize != null ? FixedTrackSize(fixedPxSize) : const IntrinsicContentTrackSize(); + } else { + return const IntrinsicContentTrackSize(); + } + }); + }) + .expand((List element) => element) + .toList(growable: false); + } else if (child is TableSectionLayoutElement) { + rows.addAll(child.children.whereType()); + } else if (child is TableRowLayoutElement) { + rows.add(child); + } + } + + // All table rows have a height intrinsic to their (spanned) contents + final List rowSizes = List.generate( + rows.length, + (_) => const IntrinsicContentTrackSize(), + ); + + // Calculate column bounds + int columnMax = 0; + List rowSpanOffsets = []; + for (final TableRowLayoutElement row in rows) { + final int cols = row.children + .whereType() + .fold(0, (int value, TableCellElement child) => value + child.colspan) + + rowSpanOffsets.fold(0, (int offset, int child) => child); + columnMax = max(cols, columnMax); + rowSpanOffsets = [ + ...rowSpanOffsets.map((int value) => value - 1).where((int value) => value > 0), + ...row.children.whereType().map((TableCellElement cell) => cell.rowspan - 1), + ]; + } + + // Place the cells in the rows/columns + final List cells = []; + final List columnRowOffset = List.generate(columnMax, (_) => 0); + final List columnColspanOffset = List.generate(columnMax, (_) => 0); + int rowi = 0; + for (final TableRowLayoutElement row in rows) { + int columni = 0; + for (final StyledElement child in row.children) { + if (columni > columnMax - 1) { + break; + } + if (child is TableCellElement) { + while (columnRowOffset[columni] > 0) { + columnRowOffset[columni] = columnRowOffset[columni] - 1; + columni += columnColspanOffset[columni].clamp(1, columnMax - columni - 1); + } + cells.add( + GridPlacement( + columnStart: columni, + columnSpan: min(child.colspan, columnMax - columni), + rowStart: rowi, + rowSpan: min(child.rowspan, rows.length - rowi), + child: CssBoxWidget( + style: child.style.merge(row.style), + child: Builder( + builder: (BuildContext context) { + final TextDirection alignment = child.style.direction ?? Directionality.of(context); + return SizedBox.expand( + child: Container( + alignment: _getCellAlignment(child, alignment), + child: CssBoxWidget.withInlineSpanChildren( + children: [ + parsedCells[child] ?? const TextSpan(text: 'error'), + ], + style: Style(), + ), + ), + ); + }, + ), + ), + ), + ); + columnRowOffset[columni] = child.rowspan - 1; + columnColspanOffset[columni] = child.colspan; + columni += child.colspan; + } + } + while (columni < columnRowOffset.length) { + columnRowOffset[columni] = columnRowOffset[columni] - 1; + columni++; + } + rowi++; + } + + // Create column tracks (insofar there were no colgroups that already defined them) + List finalColumnSizes = columnSizes.take(columnMax).toList(); + finalColumnSizes += List.generate( + max(0, columnMax - finalColumnSizes.length), + (_) => const IntrinsicContentTrackSize(), + ); + + if (finalColumnSizes.isEmpty || rowSizes.isEmpty) { + // No actual cells to show + return const SizedBox(); + } + + return LayoutGrid( + gridFit: GridFit.loose, + columnSizes: finalColumnSizes, + rowSizes: rowSizes, + children: cells, + ); +} + +Alignment _getCellAlignment(TableCellElement cell, TextDirection alignment) { + Alignment verticalAlignment; + + switch (cell.style.verticalAlign) { + case VerticalAlign.baseline: + case VerticalAlign.sub: + case VerticalAlign.sup: + case VerticalAlign.top: + verticalAlignment = Alignment.topCenter; + case VerticalAlign.middle: + verticalAlignment = Alignment.center; + case VerticalAlign.bottom: + verticalAlignment = Alignment.bottomCenter; + } + + switch (cell.style.textAlign) { + case TextAlign.left: + return verticalAlignment + Alignment.centerLeft; + case TextAlign.right: + return verticalAlignment + Alignment.centerRight; + case TextAlign.center: + return verticalAlignment + Alignment.center; + case null: + case TextAlign.start: + case TextAlign.justify: + switch (alignment) { + case TextDirection.rtl: + return verticalAlignment + Alignment.centerRight; + case TextDirection.ltr: + return verticalAlignment + Alignment.centerLeft; + } + case TextAlign.end: + switch (alignment) { + case TextDirection.rtl: + return verticalAlignment + Alignment.centerLeft; + case TextDirection.ltr: + return verticalAlignment + Alignment.centerRight; + } + } +} + +extension _ElementName on html.Node { + String get elementName { + if (this is html.Element) { + return (this as html.Element).localName ?? ''; + } + return ''; + } +} diff --git a/lib/src/components/organisms/html_preview/video_html_extension.dart b/lib/src/components/organisms/html_preview/video_html_extension.dart new file mode 100644 index 0000000..32d8f6e --- /dev/null +++ b/lib/src/components/organisms/html_preview/video_html_extension.dart @@ -0,0 +1,174 @@ +import 'dart:async'; +import 'dart:collection'; +import 'dart:io'; + +import 'package:chewie/chewie.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_html_video/flutter_html_video.dart'; +import 'package:video_player/video_player.dart'; + +/// [ZdsVideoHtmlExtension] adds support for the
, ,