diff --git a/app/CHANGELOG.md b/app/CHANGELOG.md index 71970e5e..1043d97e 100644 --- a/app/CHANGELOG.md +++ b/app/CHANGELOG.md @@ -7,16 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/Orange-OpenSource/ouds-flutter/compare/0.2.0...develop) ### Added -- [Library] `Switch` component (tokens library v0.11.0) ([##182](https://github.com/Orange-OpenSource/ouds-flutter/issues/#182) -- [Tool] Added Dependabot configuration for automatic dependency updates ([#154](https://github.com/Orange-OpenSource/ouds-flutter/issues/154)) -- [Library] `Divider` component (tokens library v0.11.0) ([#151](https://github.com/Orange-OpenSource/ouds-flutter/issues/151)) +- [DemoApp][Library] Create component - `Divider` ([#57](https://github.com/Orange-OpenSource/ouds-flutter/issues/57)) ### Changed - [DemoApp][Library] Refactor : create class global for icons names ([#152](https://github.com/Orange-OpenSource/ouds-flutter/issues/152)) -### Fixed - -- [DemoApp][Library] Clean project ouds_core ([#185](https://github.com/Orange-OpenSource/ouds-flutter/issues/185)) +### Added +- [Library] `Switch` component (tokens library v0.11.0) ([##182](https://github.com/Orange-OpenSource/ouds-flutter/issues/#182) +- [Tool] Added Dependabot configuration for automatic dependency updates ([#154](https://github.com/Orange-OpenSource/ouds-flutter/issues/154)) +- [Library] `Divider` component (tokens library v0.11.0) ([#151](https://github.com/Orange-OpenSource/ouds-flutter/issues/151)) ## [0.2.0](https://github.com/Orange-OpenSource/ouds-flutter/compare/0.1.0...0.2.0) - 2025-05-13 diff --git a/app/assets/il_components_divider.svg b/app/assets/il_components_divider.svg new file mode 100644 index 00000000..f0310b2b --- /dev/null +++ b/app/assets/il_components_divider.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/il_components_divider_dark.svg b/app/assets/il_components_divider_dark.svg new file mode 100644 index 00000000..6b688093 --- /dev/null +++ b/app/assets/il_components_divider_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/lib/l10n/gen/ouds_flutter_app_localizations.dart b/app/lib/l10n/gen/ouds_flutter_app_localizations.dart index ca850748..c5e7e59f 100644 --- a/app/lib/l10n/gen/ouds_flutter_app_localizations.dart +++ b/app/lib/l10n/gen/ouds_flutter_app_localizations.dart @@ -371,6 +371,12 @@ abstract class AppLocalizations { /// **'On colored background'** String get app_components_common_onColoredBackground_label; + /// No description provided for @app_components_common_color_label. + /// + /// In en, this message translates to: + /// **'Color'** + String get app_components_common_color_label; + /// No description provided for @app_components_button_label. /// /// In en, this message translates to: @@ -508,6 +514,30 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Open the app settings'** String get app_about_appSettings_label; + + /// No description provided for @app_components_divider_label. + /// + /// In en, this message translates to: + /// **'Divider'** + String get app_components_divider_label; + + /// No description provided for @app_components_divider_description_text. + /// + /// In en, this message translates to: + /// **'A divider visually structures an interface by clearly separating content sections. It helps to improve readability and content organization without introducing a strong hierarchy like a heading or a container would.'** + String get app_components_divider_description_text; + + /// No description provided for @app_components_divider_horizontalDivider_label. + /// + /// In en, this message translates to: + /// **'Horizontal divider'** + String get app_components_divider_horizontalDivider_label; + + /// No description provided for @app_components_divider_verticalDivider_label. + /// + /// In en, this message translates to: + /// **'Vertical divider'** + String get app_components_divider_verticalDivider_label; } class _AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/app/lib/l10n/gen/ouds_flutter_app_localizations_ar.dart b/app/lib/l10n/gen/ouds_flutter_app_localizations_ar.dart index 0f2d867a..0c9af858 100644 --- a/app/lib/l10n/gen/ouds_flutter_app_localizations_ar.dart +++ b/app/lib/l10n/gen/ouds_flutter_app_localizations_ar.dart @@ -144,6 +144,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get app_components_common_onColoredBackground_label => 'على خلفية ملوّنة'; + @override + String get app_components_common_color_label => 'اللون'; + @override String get app_components_button_label => 'زر'; @@ -212,4 +215,16 @@ class AppLocalizationsAr extends AppLocalizations { @override String get app_about_appSettings_label => 'افتح إعدادات التطبيق'; + + @override + String get app_components_divider_label => 'فاصل'; + + @override + String get app_components_divider_description_text => 'الفاصل ينظم واجهة المستخدم بصريًا عن طريق فصل أقسام المحتوى بوضوح. يساعد على تحسين قابلية القراءة وتنظيم المحتوى دون إضافة تسلسل هرمي قوي كما في العناوين أو الحاويات.'; + + @override + String get app_components_divider_horizontalDivider_label => 'فاصل أفقي'; + + @override + String get app_components_divider_verticalDivider_label => 'فاصل عمودي'; } diff --git a/app/lib/l10n/gen/ouds_flutter_app_localizations_en.dart b/app/lib/l10n/gen/ouds_flutter_app_localizations_en.dart index 973dca9f..c60176db 100644 --- a/app/lib/l10n/gen/ouds_flutter_app_localizations_en.dart +++ b/app/lib/l10n/gen/ouds_flutter_app_localizations_en.dart @@ -144,6 +144,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get app_components_common_onColoredBackground_label => 'On colored background'; + @override + String get app_components_common_color_label => 'Color'; + @override String get app_components_button_label => 'Button'; @@ -212,4 +215,16 @@ class AppLocalizationsEn extends AppLocalizations { @override String get app_about_appSettings_label => 'Open the app settings'; + + @override + String get app_components_divider_label => 'Divider'; + + @override + String get app_components_divider_description_text => 'A divider visually structures an interface by clearly separating content sections. It helps to improve readability and content organization without introducing a strong hierarchy like a heading or a container would.'; + + @override + String get app_components_divider_horizontalDivider_label => 'Horizontal divider'; + + @override + String get app_components_divider_verticalDivider_label => 'Vertical divider'; } diff --git a/app/lib/l10n/ouds_flutter_ar.arb b/app/lib/l10n/ouds_flutter_ar.arb index f29473e7..386a3082 100644 --- a/app/lib/l10n/ouds_flutter_ar.arb +++ b/app/lib/l10n/ouds_flutter_ar.arb @@ -61,6 +61,7 @@ "app_components_common_style_label": "النمط", "app_components_common_text_label": "نص", "app_components_common_onColoredBackground_label": "على خلفية ملوّنة", + "app_components_common_color_label": "اللون", "@_components_button": {}, "app_components_button_label": "زر", @@ -91,5 +92,11 @@ "app_about_legalInformation_label": "المعلومات القانونية", "app_about_materialComponents_label": "مكوّنات Material 3", "app_about_changelog_label": "سجل التغييرات", - "app_about_appSettings_label": "افتح إعدادات التطبيق" + "app_about_appSettings_label": "افتح إعدادات التطبيق", + + "@_components_divider": {}, + "app_components_divider_label": "فاصل", + "app_components_divider_description_text": "الفاصل ينظم واجهة المستخدم بصريًا عن طريق فصل أقسام المحتوى بوضوح. يساعد على تحسين قابلية القراءة وتنظيم المحتوى دون إضافة تسلسل هرمي قوي كما في العناوين أو الحاويات.", + "app_components_divider_horizontalDivider_label": "فاصل أفقي", + "app_components_divider_verticalDivider_label": "فاصل عمودي" } diff --git a/app/lib/l10n/ouds_flutter_en.arb b/app/lib/l10n/ouds_flutter_en.arb index ef80b422..3f69634b 100644 --- a/app/lib/l10n/ouds_flutter_en.arb +++ b/app/lib/l10n/ouds_flutter_en.arb @@ -61,6 +61,7 @@ "app_components_common_style_label": "Style", "app_components_common_text_label": "Text", "app_components_common_onColoredBackground_label": "On colored background", + "app_components_common_color_label": "Color", "@_components_button": {}, "app_components_button_label": "Button", @@ -91,5 +92,12 @@ "app_about_legalInformation_label": "Legal information", "app_about_materialComponents_label": "Material 3 components", "app_about_changelog_label": "Changelog", - "app_about_appSettings_label": "Open the app settings" + "app_about_appSettings_label": "Open the app settings", + + "@_components_divider": {}, + "app_components_divider_label": "Divider", + "app_components_divider_description_text": "A divider visually structures an interface by clearly separating content sections. It helps to improve readability and content organization without introducing a strong hierarchy like a heading or a container would.", + "app_components_divider_horizontalDivider_label": "Horizontal divider", + "app_components_divider_verticalDivider_label": "Vertical divider" + } diff --git a/app/lib/ui/about/about_screen.dart b/app/lib/ui/about/about_screen.dart index 41246ab8..57c1814b 100644 --- a/app/lib/ui/about/about_screen.dart +++ b/app/lib/ui/about/about_screen.dart @@ -162,7 +162,12 @@ class _AboutScreenState extends State { ), ListTile( title: Text(context.l10n.app_about_appSettings_label, - style: TextStyle(fontSize: currentTheme.fontTokens.sizeBodyLargeMobile, fontWeight: currentTheme.fontTokens.weightDefault, color: currentTheme.colorsScheme.contentBrandPrimary)), + style: TextStyle( + fontSize: currentTheme.fontTokens.sizeBodyLargeMobile, + fontWeight: currentTheme.fontTokens.weightDefault, + color: currentTheme.colorsScheme.contentBrandPrimary + ) + ), onTap: () { SettingsHelper.openAppropriateSettings(); }), diff --git a/app/lib/ui/components/button/button_demo_screen.dart b/app/lib/ui/components/button/button_demo_screen.dart index 56f5da52..76abb2d7 100644 --- a/app/lib/ui/components/button/button_demo_screen.dart +++ b/app/lib/ui/components/button/button_demo_screen.dart @@ -12,7 +12,9 @@ import 'package:flutter/material.dart'; import 'package:ouds_core/components/button/ouds_button.dart'; +import 'package:ouds_core/components/lists/ouds_list_switch.dart'; import 'package:ouds_core/components/ouds_colored_box.dart'; +import 'package:ouds_core/components/sheets_bottom/ouds_sheets_bottom.dart'; import 'package:ouds_flutter_demo/l10n/app_localizations.dart'; import 'package:ouds_flutter_demo/main_app_bar.dart'; import 'package:ouds_flutter_demo/ui/components/button/button_code_generator.dart'; @@ -24,9 +26,7 @@ import 'package:ouds_flutter_demo/ui/utilities/code.dart'; import 'package:ouds_flutter_demo/ui/utilities/component_screen_header.dart'; import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_chips.dart'; import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_section.dart'; -import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_switch.dart'; import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_textfield.dart'; -import 'package:ouds_flutter_demo/ui/utilities/sheets_bottom/ouds_sheets_bottom.dart'; import 'package:provider/provider.dart'; /// This screen displays a button demo and allows customization of button properties @@ -146,7 +146,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { return CustomizableSection( children: [ - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_common_enabled_label, value: customizationState!.hasEnabled, onChanged: @@ -158,7 +158,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { customizationState.hasEnabled = value; }, ), - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_components_common_onColoredBackground_label, value: customizationState.hasOnColoredBox, onChanged: diff --git a/app/lib/ui/components/checkbox/checkbox_demo_screen.dart b/app/lib/ui/components/checkbox/checkbox_demo_screen.dart index d20967f8..7e8ab9d8 100644 --- a/app/lib/ui/components/checkbox/checkbox_demo_screen.dart +++ b/app/lib/ui/components/checkbox/checkbox_demo_screen.dart @@ -12,7 +12,9 @@ import 'package:flutter/material.dart'; import 'package:ouds_core/components/checkbox/ouds_checkbox.dart'; +import 'package:ouds_core/components/lists/ouds_list_switch.dart'; import 'package:ouds_core/components/ouds_colored_box.dart'; +import 'package:ouds_core/components/sheets_bottom/ouds_sheets_bottom.dart'; import 'package:ouds_flutter_demo/l10n/app_localizations.dart'; import 'package:ouds_flutter_demo/main_app_bar.dart'; import 'package:ouds_flutter_demo/ui/components/checkbox/checkbox_code_generator.dart'; @@ -20,9 +22,7 @@ import 'package:ouds_flutter_demo/ui/components/checkbox/checkbox_customization. import 'package:ouds_flutter_demo/ui/theme/theme_controller.dart'; import 'package:ouds_flutter_demo/ui/utilities/code.dart'; import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_section.dart'; -import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_switch.dart'; import 'package:ouds_flutter_demo/ui/utilities/detail_screen_header.dart'; -import 'package:ouds_flutter_demo/ui/utilities/sheets_bottom/ouds_sheets_bottom.dart'; import 'package:provider/provider.dart'; /// This screen displays a checkbox demo and allows customization of checkbox properties @@ -173,7 +173,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { return CustomizableSection( children: [ - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_common_enabled_label, value: customizationState!.hasEnabled, onChanged: @@ -185,7 +185,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { customizationState.hasEnabled = value; }, ), - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_components_common_error_label, value: customizationState.hasError, onChanged: diff --git a/app/lib/ui/components/checkbox/checkbox_item_demo_screen.dart b/app/lib/ui/components/checkbox/checkbox_item_demo_screen.dart index 4e6a1fd0..c0dc902f 100644 --- a/app/lib/ui/components/checkbox/checkbox_item_demo_screen.dart +++ b/app/lib/ui/components/checkbox/checkbox_item_demo_screen.dart @@ -12,7 +12,9 @@ import 'package:flutter/material.dart'; import 'package:ouds_core/components/checkbox/ouds_checkbox_item.dart'; +import 'package:ouds_core/components/lists/ouds_list_switch.dart'; import 'package:ouds_core/components/ouds_colored_box.dart'; +import 'package:ouds_core/components/sheets_bottom/ouds_sheets_bottom.dart'; import 'package:ouds_flutter_demo/l10n/app_localizations.dart'; import 'package:ouds_flutter_demo/main_app_bar.dart'; import 'package:ouds_flutter_demo/ui/components/control_item/control_item_code_generator.dart'; @@ -22,10 +24,8 @@ import 'package:ouds_flutter_demo/ui/components/control_item/control_item_enum.d import 'package:ouds_flutter_demo/ui/theme/theme_controller.dart'; import 'package:ouds_flutter_demo/ui/utilities/code.dart'; import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_section.dart'; -import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_switch.dart'; import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_textfield.dart'; import 'package:ouds_flutter_demo/ui/utilities/detail_screen_header.dart'; -import 'package:ouds_flutter_demo/ui/utilities/sheets_bottom/ouds_sheets_bottom.dart'; import 'package:provider/provider.dart'; /// This screen displays a checkbox demo and allows customization of checkbox properties. @@ -184,7 +184,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { return CustomizableSection( children: [ - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_components_controlItem_icon_label, value: customizationState!.hasIcon, onChanged: (value) { @@ -193,7 +193,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { }); }, ), - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_components_controlItem_divider_label, value: customizationState.hasDivider, onChanged: (value) { @@ -202,7 +202,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { }); }, ), - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_components_controlItem_reversed_label, value: customizationState.hasReversed, onChanged: (value) { @@ -211,7 +211,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { }); }, ), - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_common_enabled_label, value: customizationState.hasEnabled, onChanged: customizationState.isEnabledWhenError || customizationState.isEnabledWhenReadOnly @@ -222,7 +222,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { }); }, ), - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_components_controlItem_readOnly_label, value: customizationState.hasReadOnly, onChanged: customizationState.isReadOnlyWhenError || customizationState.isReadOnlyWhenEnabled @@ -233,7 +233,7 @@ class _CustomizationContentState extends State<_CustomizationContent> { }); }, ), - CustomizableSwitch( + OudsListSwitch( title: context.l10n.app_components_common_error_label, value: customizationState.hasError, onChanged: customizationState.isErrorWhenEnabled || customizationState.isErrorWhenReadOnly diff --git a/app/lib/ui/components/components.dart b/app/lib/ui/components/components.dart index c87f9516..dd6bc304 100644 --- a/app/lib/ui/components/components.dart +++ b/app/lib/ui/components/components.dart @@ -16,6 +16,7 @@ import 'package:ouds_flutter_demo/ui/components/button/button_demo_screen.dart'; import 'package:ouds_flutter_demo/ui/components/checkbox/checkbox_demo_screen.dart'; import 'package:ouds_flutter_demo/ui/components/checkbox/checkbox_item_demo_screen.dart'; import 'package:ouds_flutter_demo/ui/components/component_entities.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/divider_demo_screen.dart'; import 'package:ouds_flutter_demo/ui/utilities/adaptive_image_helper.dart'; import 'package:ouds_flutter_demo/ui/utilities/app_assets.dart'; @@ -50,5 +51,16 @@ List components(BuildContext context) { ), ], ), + Component.withVariant( + context.l10n.app_components_divider_label, AdaptiveImageHelper.getImage(context, AppAssets.images.ilComponentsDivider), context.l10n.app_components_divider_description_text, [ + VariantComponent( + context.l10n.app_components_divider_horizontalDivider_label, + DividerDemoScreen(vertical: false), + ), + VariantComponent( + context.l10n.app_components_divider_verticalDivider_label, + DividerDemoScreen(vertical: true), + ), + ]) ]; } diff --git a/app/lib/ui/components/components_screen.dart b/app/lib/ui/components/components_screen.dart index b923a2ae..49f3ba16 100644 --- a/app/lib/ui/components/components_screen.dart +++ b/app/lib/ui/components/components_screen.dart @@ -12,13 +12,15 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:ouds_core/components/cards/ouds_cards_common.dart'; +import 'package:ouds_core/components/cards/ouds_vertical_image_first_card.dart'; import 'package:ouds_flutter_demo/ui/components/component_entities.dart'; import 'package:ouds_flutter_demo/ui/components/component_variants_screen.dart'; import 'package:ouds_flutter_demo/ui/theme/theme_controller.dart'; -import 'package:ouds_flutter_demo/ui/utilities/cards/ouds_cards_common.dart'; -import 'package:ouds_flutter_demo/ui/utilities/cards/ouds_vertical_image_first_card.dart'; import 'package:provider/provider.dart'; +import 'package:ouds_flutter_demo/ui/components/component_variants_screen.dart'; + class ComponentsScreen extends StatelessWidget { final List oudsComponents; diff --git a/app/lib/ui/components/divider/divider_code_generator.dart b/app/lib/ui/components/divider/divider_code_generator.dart new file mode 100644 index 00000000..51dc12a8 --- /dev/null +++ b/app/lib/ui/components/divider/divider_code_generator.dart @@ -0,0 +1,42 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// + +import 'package:flutter/material.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/Divider_customization_utils.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/divider_customization.dart'; + +/// +/// The CheckboxCodeGenerator class is responsible for dynamically generating Flutter +/// code for the customization of a divider component. It leverages the divider's +/// customization state, specifically the color state, and generates +/// the corresponding code in string format, which can be used for rendering or +/// previewing the divider with the selected properties. +/// +class DividerCodeGenerator { + // Static method to generate the code based on divider customization state + static String updateCode(BuildContext context, bool vertical) { + return """${functionName(vertical)}(\n${color(context)}\n)"""; + } + + // Method to get the function name according to the orientation of divider + static String functionName(bool vertical) { + // Return the function name based on the orientation of divider + return vertical == true ? 'OudsVerticalDivider' : 'OudsHorizontalDivider'; + } + + // Method to generate the selected color + static String color(BuildContext context) { + final DividerCustomizationState? customizationState = DividerCustomization.of(context); + + return "color = ${DividerCustomizationUtils.getOudsDividerColor(customizationState?.selectedColor)}"; + } +} diff --git a/app/lib/ui/components/divider/divider_customization.dart b/app/lib/ui/components/divider/divider_customization.dart new file mode 100644 index 00000000..f2a43209 --- /dev/null +++ b/app/lib/ui/components/divider/divider_customization.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/divider_enum.dart'; +import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_widget_state.dart'; + +/// Section for InheritedWidget to pass data down the widget tree +class _DividerCustomization extends InheritedWidget { + const _DividerCustomization({ + required super.child, + required this.data, + }); + + final DividerCustomizationState data; + + @override + bool updateShouldNotify(_DividerCustomization oldWidget) => true; +} + +/// Main Widget class for Divider customization +class DividerCustomization extends StatefulWidget { + const DividerCustomization({ + super.key, + required this.child, + }); + + final Widget child; + + @override + DividerCustomizationState createState() => DividerCustomizationState(); + + static DividerCustomizationState? of(BuildContext context) { + return (context.dependOnInheritedWidgetOfExactType<_DividerCustomization>())?.data; + } +} + +/// Divider customization state management +class DividerCustomizationState extends CustomizationWidgetState { + late final ColorState colorState; + + @override + void initState() { + super.initState(); + colorState = ColorState(setState); + } + + // Proxy getters and setters to expose state values directly + DividerEnumColor get selectedColor => colorState.selectedColor; + set selectedColor(DividerEnumColor value) => colorState.selectedColor = value; + + int get selectedIndex => colorState.index; + set selectedIndex(int value) => colorState.index = value; + + @override + Widget build(BuildContext context) { + return _DividerCustomization( + data: this, + child: widget.child, + ); + } +} + +/// Color State Management +class ColorState { + ColorState(this._setState); + + final void Function(void Function()) _setState; + + List _color = [ + DividerEnumColor.alwaysOnWhite, + DividerEnumColor.alwaysWhite, + DividerEnumColor.alwaysOnBlack, + DividerEnumColor.alwaysBlack, + DividerEnumColor.brandPrimary, + DividerEnumColor.defaultColor, + DividerEnumColor.emphasized, + DividerEnumColor.muted, + DividerEnumColor.onBrandPrimary, + ]; + + DividerEnumColor _selectedColor = DividerEnumColor.defaultColor; + int _selectedIndex = 5; + + List get list => _color; + set list(List newList) { + _setState(() { + _color = newList; + }); + } + + DividerEnumColor get selectedColor => _selectedColor; + set selectedColor(DividerEnumColor newValue) { + _setState(() { + _selectedColor = newValue; + }); + } + + int get index => _selectedIndex; + set index(int newValue) { + _setState(() { + _selectedIndex = newValue; + }); + } +} diff --git a/app/lib/ui/components/divider/divider_customization_utils.dart b/app/lib/ui/components/divider/divider_customization_utils.dart new file mode 100644 index 00000000..d08df990 --- /dev/null +++ b/app/lib/ui/components/divider/divider_customization_utils.dart @@ -0,0 +1,46 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// +import 'package:ouds_core/components/divider/ouds_divider.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/divider_enum.dart'; + +/// Utility class to map divider customization options to corresponding OudsDivider attributes. +/// +/// This class provides static methods to convert customization enums into the appropriate +/// [OudsDivider] properties. It includes methods for determining the divider color, +/// based on the input enum values. These methods help in translating +/// user-selected options into code that is used for button customization and rendering. + +class DividerCustomizationUtils { + /// Maps the color enum to `OudsDividerColor`. + static OudsDividerColor getOudsDividerColor(DividerEnumColor? color) { + switch (color) { + case DividerEnumColor.onBrandPrimary: + return OudsDividerColor.onBrandPrimary; + case DividerEnumColor.muted: + return OudsDividerColor.muted; + case DividerEnumColor.emphasized: + return OudsDividerColor.emphasized; + case DividerEnumColor.brandPrimary: + return OudsDividerColor.brandPrimary; + case DividerEnumColor.alwaysBlack: + return OudsDividerColor.alwaysBlack; + case DividerEnumColor.alwaysOnBlack: + return OudsDividerColor.alwaysOnBlack; + case DividerEnumColor.alwaysWhite: + return OudsDividerColor.alwaysWhite; + case DividerEnumColor.alwaysOnWhite: + return OudsDividerColor.alwaysOnWhite; + default: + return OudsDividerColor.defaultColor; + } + } +} diff --git a/app/lib/ui/components/divider/divider_demo_screen.dart b/app/lib/ui/components/divider/divider_demo_screen.dart new file mode 100644 index 00000000..845d29be --- /dev/null +++ b/app/lib/ui/components/divider/divider_demo_screen.dart @@ -0,0 +1,154 @@ +import 'package:flutter/material.dart'; +import 'package:ouds_core/components/divider/ouds_divider.dart'; +import 'package:ouds_core/components/ouds_colored_box.dart'; +import 'package:ouds_core/components/sheets_bottom/ouds_sheets_bottom.dart'; +import 'package:ouds_core/ouds_theme.dart'; +import 'package:ouds_flutter_demo/l10n/app_localizations.dart'; +import 'package:ouds_flutter_demo/main_app_bar.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/divider_code_generator.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/divider_customization.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/divider_customization_utils.dart'; +import 'package:ouds_flutter_demo/ui/components/divider/divider_enum.dart'; +import 'package:ouds_flutter_demo/ui/theme/theme_controller.dart'; +import 'package:ouds_flutter_demo/ui/utilities/code.dart'; +import 'package:ouds_flutter_demo/ui/utilities/customizable/customizable_dropdown_menu.dart'; +import 'package:ouds_flutter_demo/ui/utilities/detail_screen_header.dart'; +import 'package:provider/provider.dart'; + +class DividerDemoScreen extends StatefulWidget { + final bool vertical; + + const DividerDemoScreen({super.key, required this.vertical}); + + @override + State createState() => _DividerDemoScreenState(); +} + +class _DividerDemoScreenState extends State { + @override + Widget build(BuildContext context) { + return DividerCustomization( + child: Scaffold( + bottomSheet: OudsSheetsBottom( + sheetContent: const _CustomizationContent(), + title: context.l10n.app_common_customize_label, + ), + // key: _scaffoldKey, + appBar: widget.vertical + ? MainAppBar(title: context.l10n.app_components_divider_verticalDivider_label) // Display IndeterminateCheckboxDemo if true + : MainAppBar(title: context.l10n.app_components_divider_horizontalDivider_label), + body: SafeArea( + child: ExcludeSemantics( + //excluding: !_isBottomSheetExpanded, + child: _Body(vertical: widget.vertical), + ), + ), + )); + } +} + +class _CustomizationContent extends StatefulWidget { + const _CustomizationContent(); + + @override + State<_CustomizationContent> createState() => _CustomizationContentState(); +} + +/// This state class handles the customization options for the checkbox +class _CustomizationContentState extends State<_CustomizationContent> { + _CustomizationContentState(); + + @override + Widget build(BuildContext context) { + final DividerCustomizationState? customizationState = DividerCustomization.of(context); + + //sort alphabetic order + var colors = customizationState!.colorState.list..sort((color, colorNext) => color.formattedName.compareTo(colorNext.formattedName)); + + return CustomizationDropdownMenu( + label: DividerEnumColor.enumName(context), + options: colors, + selectedItemIndex: customizationState.selectedIndex, + selectedOption: customizationState.selectedColor, + getText: (option) => option.formattedName, + onSelectionChange: (value, index) { + setState(() { + customizationState.selectedColor = value; + customizationState.selectedIndex = index; + }); + }, + itemLeadingIcons: customizationState.colorState.list.map((color) { + return () => Container( + width: OudsTheme.of(context).spaceTokens.paddingBlockSpacious, + height: OudsTheme.of(context).spaceTokens.paddingBlockSpacious, + decoration: BoxDecoration( + color: DividerCustomizationUtils.getOudsDividerColor(color).getColor(context), + shape: BoxShape.rectangle, + ), + ); + }).toList(), + ); + } +} + +class _Body extends StatefulWidget { + final bool vertical; + + const _Body({required this.vertical}); + + @override + State<_Body> createState() => _BodyState(); +} + +class _BodyState extends State<_Body> { + @override + Widget build(BuildContext context) { + ThemeController? themeController = Provider.of(context, listen: false); + return DetailScreenDescription( + widget: Column( + children: [ + _DividerDemo(vertical: widget.vertical), + SizedBox(height: themeController.currentTheme.spaceTokens.fixedTall), + Code( + code: DividerCodeGenerator.updateCode(context, widget.vertical), + ), + ], + ), + ); + } +} + +/// This widget is now a StatefulWidget for the divider demo. +/// +/// Component [DividerDemo] demonstrates the behavior and functionality of a divider. +class _DividerDemo extends StatefulWidget { + final bool vertical; + + const _DividerDemo({required this.vertical}); + + @override + State<_DividerDemo> createState() => _DividerDemoState(); +} + +class _DividerDemoState extends State<_DividerDemo> { + ThemeController? themeController; + DividerCustomizationState? customizationState; + + @override + Widget build(BuildContext context) { + customizationState = DividerCustomization.of(context); + themeController = Provider.of(context, listen: false); + + // Adding post-frame callback to update theme based on customization state + WidgetsBinding.instance.addPostFrameCallback((_) { + themeController?.setOnColoredSurface(customizationState?.hasOnColoredBox); + }); + + return OudsColoredBox( + color: customizationState?.hasOnColoredBox == true ? OudsColoredBoxColor.brandPrimary : OudsColoredBoxColor.statusNeutralMuted, + child: widget.vertical + ? OudsDivider.vertical(color: DividerCustomizationUtils.getOudsDividerColor(customizationState?.selectedColor)) + : OudsDivider.horizontal(color: DividerCustomizationUtils.getOudsDividerColor(customizationState?.selectedColor)), + ); + } +} diff --git a/app/lib/ui/components/divider/divider_enum.dart b/app/lib/ui/components/divider/divider_enum.dart new file mode 100644 index 00000000..30ee5f9f --- /dev/null +++ b/app/lib/ui/components/divider/divider_enum.dart @@ -0,0 +1,28 @@ +import 'package:flutter/cupertino.dart'; +import 'package:ouds_flutter_demo/l10n/app_localizations.dart'; + +/// Represents the color of an OUDS divider. +enum DividerEnumColor { + defaultColor, + muted, + emphasized, + brandPrimary, + onBrandPrimary, + alwaysBlack, + alwaysOnBlack, + alwaysWhite, + alwaysOnWhite; + + static String enumName(BuildContext context) { + return context.l10n.app_components_common_color_label; + } +} + +extension FormattedName on Enum { + String get formattedName { + if (name == 'defaultColor') return 'Default'; + final words = name.split(RegExp(r'(?=\p{Lu})', unicode: true)); + final joined = words.map((w) => w.toLowerCase()).join(' ').trim(); + return joined[0].toUpperCase() + joined.substring(1); + } +} diff --git a/app/lib/ui/main_screen.dart b/app/lib/ui/main_screen.dart index c90d6fae..a1cd1419 100644 --- a/app/lib/ui/main_screen.dart +++ b/app/lib/ui/main_screen.dart @@ -11,9 +11,9 @@ */ import 'package:flutter/material.dart'; +import 'package:ouds_core/components/navigation_bar/ouds_navigation_bar.dart'; import 'package:ouds_flutter_demo/main_app_bar.dart'; -import 'package:ouds_flutter_demo/ui/navigation/navigation_bar/ouds_navigation_bar.dart'; -import 'package:ouds_flutter_demo/ui/navigation/navigation_items.dart'; +import 'package:ouds_flutter_demo/ui/utilities/navigation_items.dart'; class MainScreen extends StatefulWidget { const MainScreen({super.key}); diff --git a/app/lib/ui/tokens/token_detail_screen.dart b/app/lib/ui/tokens/token_detail_screen.dart index c534ec0b..2fc401d8 100644 --- a/app/lib/ui/tokens/token_detail_screen.dart +++ b/app/lib/ui/tokens/token_detail_screen.dart @@ -12,6 +12,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:ouds_core/components/lists/ouds_list_item.dart'; import 'package:ouds_flutter_demo/main_app_bar.dart'; import 'package:ouds_flutter_demo/ui/tokens/token_entities.dart'; import 'package:ouds_flutter_demo/ui/utilities/display_image.dart'; @@ -80,10 +81,11 @@ class VariantEntry extends StatelessWidget { @override Widget build(BuildContext context) { - return ListTile( - title: Text(variant.title), - subtitle: Text(variant.technicalName), - onTap: () { + return OudsListItem( + title: variant.title, + subtitle: variant.technicalName, + image: const Icon(Icons.play_circle_outline), + onPressed: () { Get.to(variant.screen); }, ); diff --git a/app/lib/ui/tokens/token_screen.dart b/app/lib/ui/tokens/token_screen.dart index fca3e774..5d8e7643 100644 --- a/app/lib/ui/tokens/token_screen.dart +++ b/app/lib/ui/tokens/token_screen.dart @@ -12,11 +12,11 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:ouds_core/components/cards/ouds_cards_common.dart'; +import 'package:ouds_core/components/cards/ouds_vertical_image_first_card.dart'; import 'package:ouds_flutter_demo/ui/theme/theme_controller.dart'; import 'package:ouds_flutter_demo/ui/tokens/token_detail_screen.dart'; import 'package:ouds_flutter_demo/ui/tokens/token_entities.dart'; -import 'package:ouds_flutter_demo/ui/utilities/cards/ouds_cards_common.dart'; -import 'package:ouds_flutter_demo/ui/utilities/cards/ouds_vertical_image_first_card.dart'; import 'package:provider/provider.dart'; class TokensScreen extends StatelessWidget { diff --git a/app/lib/ui/utilities/app_assets.dart b/app/lib/ui/utilities/app_assets.dart index f5dc983c..7fba5f87 100644 --- a/app/lib/ui/utilities/app_assets.dart +++ b/app/lib/ui/utilities/app_assets.dart @@ -20,11 +20,15 @@ class AppAssets { } class _Images { - _Images(); + _Images(); + /// Components final String ilComponentsButton = 'assets/il_components_button.svg'; final String ilComponentsButtonDark = 'assets/il_components_button_dark.svg'; + final String ilComponentsDivider = 'assets/il_components_divider.svg'; + final String ilComponentsDividerDark = 'assets/il_components_divider_dark.svg'; + ///Tokens final String ilTokensColor = 'assets/il_tokens_color.svg'; final String ilTokensColorDark = 'assets/il_tokens_color_dark.svg'; @@ -35,9 +39,8 @@ class _Images { final String ilTokensOpacity = 'assets/il_tokens_opacity.svg'; final String ilTokensOpacityDark = 'assets/il_tokens_opacity_dark.svg'; - final String ilUnion = 'assets/il_union.svg'; - final String ilUnionDark = 'assets/il_union_dark.svg'; - + final String ilUnion = 'assets/il_union.svg'; + final String ilUnionDark = 'assets/il_union_dark.svg'; } class _Icons { @@ -49,6 +52,7 @@ class _Icons { final String icThemeSystem = 'assets/ic_theme_system.svg'; final String icToken = 'assets/ic_token.svg'; } + class _Fonts { const _Fonts(); } diff --git a/app/lib/ui/utilities/customizable/customizable_chips.dart b/app/lib/ui/utilities/customizable/customizable_chips.dart index b5a3879e..8ed6f496 100644 --- a/app/lib/ui/utilities/customizable/customizable_chips.dart +++ b/app/lib/ui/utilities/customizable/customizable_chips.dart @@ -11,6 +11,7 @@ // import 'package:flutter/material.dart'; +import 'package:ouds_core/components/chips/ouds_choice_chips.dart'; import 'package:ouds_flutter_demo/l10n/app_localizations.dart'; import 'package:ouds_flutter_demo/ui/theme/theme_controller.dart'; import 'package:provider/provider.dart'; @@ -78,13 +79,11 @@ class CustomizableChips extends StatelessWidget { start: themeController.currentTheme.spaceTokens.scaledShortestMobile, end: themeController.currentTheme.spaceTokens.scaledShorterMobile, ), - child: ChoiceChip( - label: Text(getText(currentElement)), // Use getText to get the label + child: OudsChoiceChip( + text: getText(currentElement), selected: isSelected, - onSelected: (bool selected) { - if (selected) { - onSelected(currentElement); // Call the onSelected callback - } + onClick: (selected) { + onSelected(currentElement); }, ), ); diff --git a/app/lib/ui/utilities/customizable/customizable_dropdown_menu.dart b/app/lib/ui/utilities/customizable/customizable_dropdown_menu.dart new file mode 100644 index 00000000..e5483872 --- /dev/null +++ b/app/lib/ui/utilities/customizable/customizable_dropdown_menu.dart @@ -0,0 +1,102 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// +import 'package:flutter/material.dart'; +import 'package:ouds_core/ouds_theme.dart'; +import 'package:ouds_flutter_demo/ui/theme/theme_controller.dart'; +import 'package:provider/provider.dart'; + +class CustomizationDropdownMenu extends StatelessWidget { + final String label; + final List options; + int selectedItemIndex; + final String Function(T) getText; + final Function(T, int) onSelectionChange; + final List? itemLeadingIcons; + T? selectedOption; + + var isSelected = false; + + CustomizationDropdownMenu({ + super.key, + required this.label, + required this.options, + required this.selectedItemIndex, + required this.onSelectionChange, + required this.selectedOption, + this.itemLeadingIcons, + required this.getText, + }); + + @override + Widget build(BuildContext context) { + final themeController = Provider.of(context, listen: false); + final currentTheme = themeController.currentTheme; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsetsDirectional.symmetric(horizontal: currentTheme.spaceTokens.fixedMedium), + child: Text( + label, + style: TextStyle( + fontSize: themeController.currentTheme.fontTokens.sizeBodyLargeMobile, + fontWeight: themeController.currentTheme.fontTokens.weightLabelStrong, + letterSpacing: themeController.currentTheme.fontTokens.letterSpacingBodyLargeMobile, + ), + ), + ), + Padding( + padding: EdgeInsetsDirectional.symmetric(horizontal: currentTheme.spaceTokens.fixedMedium, vertical: currentTheme.spaceTokens.fixedShorter), + child: DropdownMenu( + initialSelection: options[selectedItemIndex], + expandedInsets: EdgeInsets.zero, + inputDecorationTheme: const InputDecorationTheme(isDense: true), + textStyle: TextStyle( + fontSize: OudsTheme.of(context).fontTokens.sizeBodyLargeMobile, + fontWeight: OudsTheme.of(context).fontTokens.weightLabelStrong, + letterSpacing: OudsTheme.of(context).fontTokens.letterSpacingBodyLargeMobile, + ), + onSelected: (value) { + if (value != null) { + selectedItemIndex = options.indexOf(value); + onSelectionChange(value, selectedItemIndex); + } + }, + leadingIcon: itemLeadingIcons != null ? buildDropdownLeadingIcon(context, itemLeadingIcons, selectedItemIndex) : null, + dropdownMenuEntries: List.generate(options.length, (index) { + selectedOption = options[index]; + selectedItemIndex = index; + return DropdownMenuEntry( + labelWidget: Text(getText(options[index]), + style: TextStyle( + fontSize: OudsTheme.of(context).fontTokens.sizeBodyLargeMobile, + fontWeight: OudsTheme.of(context).fontTokens.weightLabelStrong, + letterSpacing: OudsTheme.of(context).fontTokens.letterSpacingBodyLargeMobile, + )), + value: selectedOption as T, + label: getText(options[index]), + leadingIcon: itemLeadingIcons != null ? buildDropdownLeadingIcon(context, itemLeadingIcons, selectedItemIndex) : null, + ); + }), + ), + ), + ], + ); + } + + Widget? buildDropdownLeadingIcon(BuildContext context, List? builders, int index) { + if (builders != null && index < builders.length) { + return Padding(padding: EdgeInsetsDirectional.all(OudsTheme.of(context).spaceTokens.paddingInlineShort), child: builders[index]()); + } + return null; + } +} diff --git a/app/lib/ui/utilities/customizable/customizable_switch.dart b/app/lib/ui/utilities/customizable/customizable_switch.dart deleted file mode 100644 index 0379ea44..00000000 --- a/app/lib/ui/utilities/customizable/customizable_switch.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// Software Name: OUDS Flutter -// SPDX-FileCopyrightText: Copyright (c) Orange SA -// SPDX-License-Identifier: MIT -// -// This software is distributed under the MIT license, -// the text of which is available at https://opensource.org/license/MIT/ -// or see the "LICENSE" file for more details. -// -// Software description: Flutter library of reusable graphical components -// - -import 'package:flutter/material.dart'; -import 'package:ouds_flutter_demo/ui/theme/theme_controller.dart'; -import 'package:provider/provider.dart'; - -class CustomizableSwitch extends StatelessWidget { - final String title; - final bool value; - final void Function(bool)? onChanged; - - const CustomizableSwitch({super.key, required this.title, required this.value, this.onChanged}); - - @override - Widget build(BuildContext context) { - final themeController = Provider.of(context, listen: false); - - return SwitchListTile( - title: Text( - title, - textAlign: TextAlign.start, - style: TextStyle( - fontSize: themeController.currentTheme.fontTokens.sizeBodyLargeMobile, - fontWeight: themeController.currentTheme.fontTokens.weightLabelStrong, - letterSpacing: themeController.currentTheme.fontTokens.letterSpacingBodyLargeMobile, - ), - ), - value: value, - onChanged: onChanged, - ); - } -} diff --git a/app/lib/ui/navigation/navigation_items.dart b/app/lib/ui/utilities/navigation_items.dart similarity index 70% rename from app/lib/ui/navigation/navigation_items.dart rename to app/lib/ui/utilities/navigation_items.dart index 327e8392..c82956e6 100644 --- a/app/lib/ui/navigation/navigation_items.dart +++ b/app/lib/ui/utilities/navigation_items.dart @@ -11,11 +11,12 @@ // import 'package:flutter/material.dart'; +import 'package:ouds_core/components/navigation_bar/ouds_navigation_bar_item.dart'; +import 'package:ouds_core/components/navigation_rail/ouds_navigation_rail_item.dart'; import 'package:ouds_flutter_demo/l10n/app_localizations.dart'; import 'package:ouds_flutter_demo/ui/about/about_screen.dart'; import 'package:ouds_flutter_demo/ui/components/components.dart'; import 'package:ouds_flutter_demo/ui/components/components_screen.dart'; -import 'package:ouds_flutter_demo/ui/navigation/navigation_bar/ouds_navigation_bar_item.dart'; import 'package:ouds_flutter_demo/ui/tokens/token_screen.dart'; import 'package:ouds_flutter_demo/ui/tokens/tokens.dart'; import 'package:ouds_flutter_demo/ui/utilities/app_assets.dart'; @@ -23,6 +24,7 @@ import 'package:ouds_flutter_demo/ui/utilities/app_assets.dart'; class NavigationItems { late BuildContext context; late List _destinationsStatic; + late List _destinationsRailStatic; late List _screens; NavigationItems(this.context) { @@ -44,6 +46,24 @@ class NavigationItems { ), ]; + _destinationsRailStatic = [ + OudsNavigationRailItem( + context: context, + label: context.l10n.app_bottomBar_tokens_label, + icon: AppAssets.icons.icToken, + ), + OudsNavigationRailItem( + context: context, + label: context.l10n.app_bottomBar_components_label, + icon: AppAssets.icons.icAtom, + ), + OudsNavigationRailItem( + context: context, + label: context.l10n.app_bottomBar_about_label, + icon: AppAssets.icons.icAbout, + ), + ]; + _screens = [ TokensScreen( oudsTokens: tokens(context), @@ -63,6 +83,10 @@ class NavigationItems { return _destinationsStatic; } + getNavigationRailDestinations() { + return _destinationsRailStatic; + } + getScreens(int index) { return _screens[index]; } diff --git a/ouds_core/CHANGELOG.md b/ouds_core/CHANGELOG.md index be2d9876..81651238 100644 --- a/ouds_core/CHANGELOG.md +++ b/ouds_core/CHANGELOG.md @@ -6,8 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/Orange-OpenSource/ouds-flutter/compare/0.2.0...develop) -### Fixed -- [Library] Clean project ouds_core ([#185](https://github.com/Orange-OpenSource/ouds-flutter/issues/185)) +### Added +- [Library] Create component - Divider ([#57](https://github.com/Orange-OpenSource/ouds-flutter/issues/57)) ## [0.2.0](https://github.com/Orange-OpenSource/ouds-flutter/compare/0.1.0...0.2.0) - 2025-05-13 diff --git a/app/lib/ui/utilities/cards/ouds_cards_common.dart b/ouds_core/lib/components/cards/ouds_cards_common.dart similarity index 100% rename from app/lib/ui/utilities/cards/ouds_cards_common.dart rename to ouds_core/lib/components/cards/ouds_cards_common.dart diff --git a/app/lib/ui/utilities/cards/ouds_vertical_image_first_card.dart b/ouds_core/lib/components/cards/ouds_vertical_image_first_card.dart similarity index 93% rename from app/lib/ui/utilities/cards/ouds_vertical_image_first_card.dart rename to ouds_core/lib/components/cards/ouds_vertical_image_first_card.dart index 825b4129..c2a768b9 100644 --- a/app/lib/ui/utilities/cards/ouds_vertical_image_first_card.dart +++ b/ouds_core/lib/components/cards/ouds_vertical_image_first_card.dart @@ -11,8 +11,8 @@ // import 'package:flutter/material.dart'; +import 'package:ouds_core/components/cards/ouds_cards_common.dart'; import 'package:ouds_core/ouds_theme.dart'; -import 'package:ouds_flutter_demo/ui/utilities/cards/ouds_cards_common.dart'; /// OUDS Vertical image first card with optional custom content. /// Allows displaying either an image or a custom widget inside the card. @@ -26,7 +26,7 @@ class OudsVerticalImageFirstCard extends StatelessWidget { this.onClick, }); - static const double _imageHeight = 180; + static const double _imageHeight = 184; /// The optional image displayed in the card. final OudsCardImage? image; @@ -63,7 +63,7 @@ class OudsVerticalImageFirstCard extends StatelessWidget { ), ), Padding( - padding: const EdgeInsetsDirectional.symmetric(horizontal: 20.0, vertical: 15.0), + padding: const EdgeInsetsDirectional.symmetric(horizontal: 25.0, vertical: 25.0), child: Text( title, style: TextStyle( diff --git a/ouds_core/lib/components/chips/ouds_chip_common.dart b/ouds_core/lib/components/chips/ouds_chip_common.dart new file mode 100644 index 00000000..642885b4 --- /dev/null +++ b/ouds_core/lib/components/chips/ouds_chip_common.dart @@ -0,0 +1,81 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// + +import 'package:flutter/material.dart'; + +/// +/// A leading icon in an [OusChip]. +/// +/// Creates an instance of [OudsChipLeadingIcon]. +/// * [image] - Text to be displayed into the chip +/// * [contentDescription] - Callback called on chip click. +/// +class OudsChipLeadingIcon extends StatelessWidget { + const OudsChipLeadingIcon(this.image, this.contentDescription, {super.key}); + + /// The image associated to this [OudsChipLeadingAvatar]. + final ImageProvider image; + + /// The content description associated to this [OudsChipLeadingAvatar]. + final String? contentDescription; + + @override + Widget build(BuildContext context) { + return Image( + image: image, + width: 24, + height: 24, + fit: BoxFit.contain, + semanticLabel: contentDescription, + ); + } +} + +/// +/// A leading icon in an [OudsChip]. +/// +/// Creates an instance of [OudsChipLeadingAvatar]. +/// * [image] - Text to be displayed into the chip +/// * [contentDescription] - Callback called on chip click. +/// +class OudsChipLeadingAvatar extends StatelessWidget { + const OudsChipLeadingAvatar({ + super.key, + required this.image, + this.contentDescription, + }); + + /// The image associated to this [OudsChipLeadingAvatar]. + final ImageProvider image; + + /// The content description associated to this [OudsChipLeadingAvatar]. + final String? contentDescription; + + @override + Widget build(BuildContext context) { + Widget circleAvatar = CircleAvatar( + backgroundImage: image, + radius: 12, + backgroundColor: Colors.transparent, + ); + + if (contentDescription != null) { + circleAvatar = Semantics( + label: contentDescription!, + image: true, + child: circleAvatar, + ); + } + + return circleAvatar; + } +} diff --git a/ouds_core/lib/components/chips/ouds_choice_chips.dart b/ouds_core/lib/components/chips/ouds_choice_chips.dart new file mode 100644 index 00000000..2b71e5c9 --- /dev/null +++ b/ouds_core/lib/components/chips/ouds_choice_chips.dart @@ -0,0 +1,65 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// + +import 'package:flutter/material.dart'; +import 'package:ouds_core/components/chips/ouds_chip_common.dart'; + +/// OUDS Design Choice Chips. +/// +/// Displays a customizable chips with an optional action. +/// +class OudsChoiceChip extends StatelessWidget { + /// Creates an OUDS Choice Chip. + /// Creates an OUDS Choice Chip. + /// + /// * [text] - Text to be displayed into the chip + /// * [onClick] - Callback called on chip click. + /// * [enabled] - The action to be executed when the chips is pressed. + /// * [leadingAvatar] - Widget of the icon. + /// * [selected] - Specifies whether the chips is selected or not. + /// + const OudsChoiceChip({ + super.key, + required this.text, + this.onClick, + this.enabled = true, + this.selected = false, + this.leadingAvatar, + }); + + /// Text to be displayed into the chip. + final String text; + + /// Callback called on chip click + final void Function(bool?)? onClick; + + /// Specifies whether the chips is selected or not. + final bool enabled; + + /// Specifies whether the chips is selected or not. + final bool selected; + + /// The optional chip's icon. + final OudsChipLeadingAvatar? leadingAvatar; + + @override + Widget build(BuildContext context) { + return ChoiceChip( + label: Semantics( + child: Text(text), + ), + onSelected: enabled != false ? onClick : null, + selected: selected, + avatar: leadingAvatar, + ); + } +} diff --git a/ouds_core/lib/components/divider/ouds_divider.dart b/ouds_core/lib/components/divider/ouds_divider.dart new file mode 100644 index 00000000..ae126e0d --- /dev/null +++ b/ouds_core/lib/components/divider/ouds_divider.dart @@ -0,0 +1,112 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// + +import 'package:flutter/material.dart'; +import 'package:ouds_core/ouds_theme.dart'; + +/// TODO Add DSM link when available +/// An [OUDS Divider] component as per the design guidelines of OUDS. +/// +/// Dividers are used to visually structure an interface by clearly separating content sections. It helps to improve readability and content organization +/// without introducing a strong hierarchy like a heading or a container would. +/// +/// You can choose the orientation by using one of the named constructors: +/// - [OudsDivider.horizontal] +/// - [OudsDivider.vertical] +/// +/// The following parameters are available: +/// - [color] The color of the divider, chosen from the [OudsDividerColor] enum. +/// Default value set to [OudsDividerColor.defaultColor]. +/// - [length] The length of the divider (width for horizontal, height for vertical). +/// Defaults to [double.infinity]. +/// - [thickness] The thickness of the divider (height for horizontal, width for vertical). +/// Defaults to `1.0`. +/// - [margin] Optional margin around the divider, for spacing from surrounding content. +/// + +/// Represents the available colors for [OudsDivider]. +enum OudsDividerColor { + defaultColor, + muted, + emphasized, + brandPrimary, + onBrandPrimary, + alwaysBlack, + alwaysOnBlack, + alwaysWhite, + alwaysOnWhite; + + Color getColor(BuildContext context) { + final theme = OudsTheme.of(context); + + switch (this) { + case OudsDividerColor.muted: + return theme.colorsScheme.borderMuted; + case OudsDividerColor.emphasized: + return theme.colorsScheme.borderEmphasized; + case OudsDividerColor.brandPrimary: + return theme.colorsScheme.borderBrandPrimary; + case OudsDividerColor.onBrandPrimary: + return theme.colorsScheme.borderOnBrandPrimary; + case OudsDividerColor.alwaysBlack: + return theme.colorsScheme.alwaysBlack; + case OudsDividerColor.alwaysOnBlack: + return theme.colorsScheme.alwaysOnBlack; + case OudsDividerColor.alwaysWhite: + return theme.colorsScheme.alwaysWhite; + case OudsDividerColor.alwaysOnWhite: + return theme.colorsScheme.alwaysOnWhite; + default: + return theme.colorsScheme.borderDefault; + } + } +} + +class OudsDivider extends StatelessWidget { + final Axis orientation; + final OudsDividerColor color; + final double length; + final double? thickness; + final EdgeInsetsGeometry? margin; + + /// Creates a horizontal divider. + const OudsDivider.horizontal({ + super.key, + this.color = OudsDividerColor.defaultColor, + this.length = double.infinity, + this.thickness, + this.margin, + }) : orientation = Axis.horizontal; + + /// Creates a vertical divider. + const OudsDivider.vertical({ + super.key, + this.color = OudsDividerColor.defaultColor, + this.length = 0, + this.thickness, + this.margin, + }) : orientation = Axis.vertical; + + @override + Widget build(BuildContext context) { + final actualThickness = thickness ?? OudsTheme.of(context).componentsTokens.divider.borderWidth; + + final divider = Container( + color: color.getColor(context), + width: orientation == Axis.horizontal ? length : actualThickness, + height: orientation == Axis.horizontal ? actualThickness : 50, + margin: margin, + ); + + return Padding(padding: EdgeInsetsDirectional.all(OudsTheme.of(context).spaceTokens.fixedMedium), child: divider); + } +} diff --git a/ouds_core/lib/components/lists/ouds_list_item.dart b/ouds_core/lib/components/lists/ouds_list_item.dart new file mode 100644 index 00000000..9cec6fba --- /dev/null +++ b/ouds_core/lib/components/lists/ouds_list_item.dart @@ -0,0 +1,138 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// + +import 'package:flutter/material.dart'; +import 'package:ouds_core/components/divider/ouds_divider.dart'; + +/// OUDS List Standard +/// +/// This list contains content and actions about a single subject. +/// +/// A ripple effect is managed on list tile. +class OudsListItem extends StatelessWidget { + /// Creates an ODS List selection. + const OudsListItem({ + super.key, + required this.title, + this.subtitle, + this.image, + this.text, + this.icon, + this.value, + this.onChangedSwitch, + this.onChangedCheckBox, + this.divider, + this.onPressed, + }); + + /// The list's title . + final String title; + + /// The optional list's subtitle displayed below the title. + final String? subtitle; + + /// The image displayed in the list. + ///TODO For the moment the fit of the image is handled by the provided image. It should be done in the library but we need help to do that! + final Widget? image; + + /// The text displayed in the list trailing. + final String? text; + + /// The icon displayed in the list trailing. + final Widget? icon; + + /// The optional switch or checkbox. + final bool? value; + + /// The action executed change the switch. + final Function(bool?)? onChangedSwitch; + + /// The action executed change the checkbox. + final Function(bool?)? onChangedCheckBox; + + /// The divider displayed in the list. + final bool? divider; + + /// The action to be executed when the item is pressed. + final void Function()? onPressed; + + @override + Widget build(BuildContext context) { + return Semantics( + container: true, + child: MergeSemantics( + child: Column( + children: [ + if (onChangedSwitch != null) + SwitchListTile( + secondary: image, + title: Text( + title, + style: Theme.of(context).textTheme.titleSmall, + ), + subtitle: subtitle != null + ? Text( + subtitle!, + style: Theme.of(context).textTheme.bodyMedium, + ) + : null, + value: value ?? false, + onChanged: onChangedSwitch, + ), + if (onChangedCheckBox != null) + CheckboxListTile( + secondary: image, + title: Text( + title, + style: Theme.of(context).textTheme.titleSmall, + ), + subtitle: subtitle != null + ? Text( + subtitle!, + style: Theme.of(context).textTheme.bodyMedium, + ) + : null, + value: value ?? false, + onChanged: onChangedCheckBox, + ), + if (onChangedSwitch == null && onChangedCheckBox == null) + Semantics( + button: onPressed != null ? true : false, + child: ListTile( + leading: image, + title: Text( + title, + style: Theme.of(context).textTheme.titleSmall, + ), + subtitle: subtitle != null + ? Text( + subtitle!, + style: Theme.of(context).textTheme.bodyMedium, + ) + : null, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (text != null) Text(text!), + if (icon != null) icon!, // icon-2 + ], + ), + onTap: onPressed, + ), + ), + if (divider != null) const OudsDivider.vertical(color: OudsDividerColor.muted), + ], + ), + ), + ); + } +} diff --git a/ouds_core/lib/components/lists/ouds_list_switch.dart b/ouds_core/lib/components/lists/ouds_list_switch.dart new file mode 100644 index 00000000..1010930a --- /dev/null +++ b/ouds_core/lib/components/lists/ouds_list_switch.dart @@ -0,0 +1,77 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// + +import 'package:flutter/material.dart'; +import 'package:ouds_core/components/utilities/ouds_switch_icon.dart'; +import 'package:ouds_core/ouds_theme.dart'; + +/// OUDS OudsListSwitch. +/// +/// The OudsListSwitch widget represents a switch list element that can be checked or unchecked. +/// It allows for handling the OudsListSwitch list state and triggering a callback when its state changes. +/// * [value] determines whether this switch is on or off. +/// * [onChanged] is called when the user toggles the switch on or off. +class OudsListSwitch extends StatelessWidget { + /// Creates an OUDS Switch list. + const OudsListSwitch({ + super.key, + required this.title, + required this.value, + required this.onChanged, + this.icon, + this.enabled = true, + }); + + /// The primary content of the list tile. + final String title; + + /// Determines whether this switch is on or off. + final bool value; + + /// A callback function to handle changes in the checked state. + final void Function(bool)? onChanged; + + /// The icon to use on the thumb of this switch. + final bool? icon; + + /// Controls the enabled state of the switch. When false, this button will not be clickable. + final bool? enabled; + + @override + Widget build(BuildContext context) { + String switchValue = + value ? 'Checked' : 'Unchecked'; + + OudsSwitchIcon oudsSwitchIcon = OudsSwitchIcon(context); + + return Semantics( + label: title, + value: switchValue, + enabled: enabled, + button: true, + excludeSemantics: true, + child: SwitchListTile( + title: Text( + title, + style: TextStyle( + fontSize: OudsTheme.of(context).fontTokens.sizeBodyLargeMobile, + fontWeight: OudsTheme.of(context).fontTokens.weightLabelStrong, + letterSpacing: OudsTheme.of(context).fontTokens.letterSpacingBodyLargeMobile, + ), + ), + value: value, + onChanged: enabled != false ? onChanged : null, + thumbIcon: icon == true ? oudsSwitchIcon.thumbIcon : null, + ), + ); + } +} diff --git a/app/lib/ui/navigation/navigation_bar/ouds_navigation_bar.dart b/ouds_core/lib/components/navigation_bar/ouds_navigation_bar.dart similarity index 93% rename from app/lib/ui/navigation/navigation_bar/ouds_navigation_bar.dart rename to ouds_core/lib/components/navigation_bar/ouds_navigation_bar.dart index b549504a..dd38143d 100644 --- a/app/lib/ui/navigation/navigation_bar/ouds_navigation_bar.dart +++ b/ouds_core/lib/components/navigation_bar/ouds_navigation_bar.dart @@ -12,7 +12,7 @@ /// @nodoc import 'package:flutter/material.dart'; -import 'package:ouds_flutter_demo/ui/navigation/navigation_bar/ouds_navigation_bar_item.dart'; +import 'package:ouds_core/components/navigation_bar/ouds_navigation_bar_item.dart'; /// /// OUDS Navigation Bar. diff --git a/app/lib/ui/navigation/navigation_bar/ouds_navigation_bar_item.dart b/ouds_core/lib/components/navigation_bar/ouds_navigation_bar_item.dart similarity index 100% rename from app/lib/ui/navigation/navigation_bar/ouds_navigation_bar_item.dart rename to ouds_core/lib/components/navigation_bar/ouds_navigation_bar_item.dart diff --git a/ouds_core/lib/components/navigation_rail/ouds_navigation_rail.dart b/ouds_core/lib/components/navigation_rail/ouds_navigation_rail.dart new file mode 100644 index 00000000..280614cd --- /dev/null +++ b/ouds_core/lib/components/navigation_rail/ouds_navigation_rail.dart @@ -0,0 +1,86 @@ +/* + * Software Name : OUDS Flutter + * SPDX-FileCopyrightText: Copyright (c) Orange SA + * SPDX-License-Identifier: MIT + * + * This software is distributed under the MIT license, + * the text of which is available at https://opensource.org/license/MIT/ + * or see the "LICENSE" file for more details. + * + * Software description: Flutter library of reusable graphical components for Android and iOS + */ + +/// @nodoc +import 'package:flutter/material.dart'; +import 'package:ouds_core/components/navigation_rail/ouds_navigation_rail_item.dart'; + +/// OUDS Navigation Rail. +/// +/// The Navigation Rail is meant to be displayed at the left or right of an app to navigate between +/// a small number of views, typically between three and five. +class OudsNavigationRail extends StatelessWidget { + /// Creates an ODS Button. + /// + /// * [selectedIndex] - The index into [destinations] for the current selected NavigationRailDestination or null if no destination is selected. + /// * [destinations] - Defines the appearance of the button items that are arrayed within the navigation rail. + /// * [onDestinationSelected] - Called when one of the destinations is selected. + /// * [leadingIconFirst] - The first leading widget in the rail that is placed above the destinations. + /// * [leadingIconSecond] - The second leading widget in the rail that is placed above the destinations. + const OudsNavigationRail({ + super.key, + required this.selectedIndex, + required this.destinations, + this.onDestinationSelected, + this.leadingIconFirst, + this.leadingIconSecond, + }); + + /// The index into [destinations] for the current selected NavigationRailDestination or null if no destination is selected. + final int selectedIndex; + + /// Defines the appearance of the button items that are arrayed within the navigation rail. + final List destinations; + + /// The callback function called when one of the destinations is selected.. + final void Function(int)? onDestinationSelected; + + /// The first leading widget in the rail that is placed above the destinations. + final Widget? leadingIconFirst; + + /// The second leading widget in the rail that is placed above the destinations. + final Widget? leadingIconSecond; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + LayoutBuilder( + builder: (context, constraint) { + return SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: constraint.maxHeight), + child: IntrinsicHeight( + child: NavigationRail( + selectedIndex: selectedIndex, + onDestinationSelected: onDestinationSelected, + destinations: destinations, + labelType: NavigationRailLabelType.all, + leading: leadingIconFirst != null || leadingIconSecond != null + ? Column( + children: [ + if (leadingIconFirst != null) leadingIconFirst!, + if (leadingIconSecond != null) leadingIconSecond!, + const SizedBox(height: 32.0), + ], + ) + : null, + ), + ), + ), + ); + }, + ), + ], + ); + } +} diff --git a/ouds_core/lib/components/navigation_rail/ouds_navigation_rail_item.dart b/ouds_core/lib/components/navigation_rail/ouds_navigation_rail_item.dart new file mode 100644 index 00000000..c6fcce26 --- /dev/null +++ b/ouds_core/lib/components/navigation_rail/ouds_navigation_rail_item.dart @@ -0,0 +1,76 @@ +/* + * Software Name : OUDS Flutter + * SPDX-FileCopyrightText: Copyright (c) Orange SA + * SPDX-License-Identifier: MIT + * + * This software is distributed under the MIT license, + * the text of which is available at https://opensource.org/license/MIT/ + * or see the "LICENSE" file for more details. + * + * Software description: Flutter library of reusable graphical components for Android and iOS + */ + +/// @nodoc +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +/// OUDS Navigation Rail Item. +/// +/// Creates a destination that is used with NavigationRailItem.destinations. +class OudsNavigationRailItem extends NavigationRailDestination { + OudsNavigationRailItem({ + Key? key, + required dynamic icon, + String? badge, + required String label, + required BuildContext context, + }) : super( + icon: _buildIcon(icon, badge, context), + label: Text(label), + selectedIcon: _buildIcon(icon, badge, context, isSelected: true), + ); + + static Widget _buildIcon(dynamic iconData, String? badge, BuildContext context, {bool isSelected = false}) { + var colorScheme = Theme.of(context).colorScheme; + var colorFilter = isSelected ? ColorFilter.mode(colorScheme.onPrimary, BlendMode.srcIn) : ColorFilter.mode(colorScheme.primary, BlendMode.srcIn); + + /// If the type is IconType.icon, use the provided icon (of type Icon) + Widget iconWidget = iconData is Widget + ? iconData + + /// If the type is IconType.svg, use the SVG icon + : (iconData is String && iconData.endsWith('.svg') + ? Semantics( + excludeSemantics: true, + child: SvgPicture.asset( + iconData, + colorFilter: colorFilter, + width: 26.0, + height: 26.0, + ), + ) + + /// If the type is IconType.png, use the PNG icon + : (iconData is String && iconData.endsWith('.png') + ? Semantics( + excludeSemantics: true, + child: Image.asset(iconData), + ) + : throw Exception('Invalid icon type: ${iconData.runtimeType}'))); + + /// If the odsBottomNavigationItemIcon.badge parameter is not empty, use the Widget Badge + return badge != null + ? Badge( + label: Semantics( + label: badge, + excludeSemantics: true, + child: Text( + badge, + textScaler: TextScaler.linear(1.0), + ), + ), + child: iconWidget, + ) + : iconWidget; + } +} diff --git a/app/lib/ui/utilities/sheets_bottom/ouds_sheets_bottom.dart b/ouds_core/lib/components/sheets_bottom/ouds_sheets_bottom.dart similarity index 100% rename from app/lib/ui/utilities/sheets_bottom/ouds_sheets_bottom.dart rename to ouds_core/lib/components/sheets_bottom/ouds_sheets_bottom.dart diff --git a/ouds_core/lib/components/utilities/ouds_switch_icon.dart b/ouds_core/lib/components/utilities/ouds_switch_icon.dart new file mode 100644 index 00000000..bcd1c270 --- /dev/null +++ b/ouds_core/lib/components/utilities/ouds_switch_icon.dart @@ -0,0 +1,50 @@ +// +// Software Name: OUDS Flutter +// SPDX-FileCopyrightText: Copyright (c) Orange SA +// SPDX-License-Identifier: MIT +// +// This software is distributed under the MIT license, +// the text of which is available at https://opensource.org/license/MIT/ +// or see the "LICENSE" file for more details. +// +// Software description: Flutter library of reusable graphical components +// + +import 'package:flutter/material.dart'; + +/// Class that encapsulates the logic for generating the thumb icon for the Switch. +class OudsSwitchIcon { + final BuildContext context; + + /// Constructor that takes a BuildContext. + OudsSwitchIcon(this.context); + + /// Getter for the thumbIcon property. + WidgetStateProperty? get thumbIcon { + /// Determine if the current theme is light or dark. + final isLightTheme = Theme.of(context).brightness == Brightness.light; + + return WidgetStateProperty.resolveWith((Set states) { + /// If the Switch is both disabled and selected. + if (states.contains(WidgetState.disabled) && + states.contains(WidgetState.selected)) { + return Icon(Icons.check, + color: isLightTheme ? Colors.grey[400] : Colors.black87); + } + + /// If the Switch is selected. + if (states.contains(WidgetState.selected)) { + return const Icon(Icons.check, color: Colors.black); + } + + /// If the Switch is disabled. + if (states.contains(WidgetState.disabled)) { + return Icon(Icons.close, + color: isLightTheme ? Colors.grey[200] : Colors.grey[600]); + } + + /// Default case: Return a close icon with a fixed white color. + return const Icon(Icons.close, color: Colors.white); + }); + } +} diff --git a/ouds_theme_contract/lib/theme/tokens/components/ouds_divider_tokens.dart b/ouds_theme_contract/lib/theme/tokens/components/ouds_divider_tokens.dart index d16cf15e..0af4d9e5 100644 --- a/ouds_theme_contract/lib/theme/tokens/components/ouds_divider_tokens.dart +++ b/ouds_theme_contract/lib/theme/tokens/components/ouds_divider_tokens.dart @@ -13,15 +13,10 @@ // Tokens version 0.11.0 // Generated by Tokenator -import 'package:flutter/material.dart'; import 'package:ouds_theme_contract/ouds_tokens_provider.dart'; class OudsDividerTokens { final double borderWidth; - OudsDividerTokens({ - required OudsProvidersTokens providersTokens, - double? borderWidth - }) : - borderWidth = borderWidth ?? providersTokens.borderTokens.widthThin; + OudsDividerTokens({required OudsProvidersTokens providersTokens, double? borderWidth}) : borderWidth = borderWidth ?? providersTokens.borderTokens.widthThin; }