From d4bbc99052495d222883e8460ed3bb42cbb27866 Mon Sep 17 00:00:00 2001 From: Andre Rossi Date: Fri, 31 Jan 2025 14:38:33 -0300 Subject: [PATCH 1/6] dark mode support --- devtools_options.yaml | 3 + lib/blip_ds.dart | 1 + lib/src/services/ds_bottom_sheet.service.dart | 62 +++++++++++-------- lib/src/services/ds_dialog.service.dart | 8 ++- lib/src/services/ds_theme.service.dart | 15 +++++ .../audio/ds_audio_icon_button.widget.dart | 5 +- .../audio/ds_audio_resume_button.widget.dart | 10 +-- .../buttons/ds_attachment_button.widget.dart | 5 +- .../ds_custom_replies_icon_button.widget.dart | 7 ++- .../buttons/ds_secondary_button.widget.dart | 11 +++- .../buttons/ds_tertiary_button.widget.dart | 9 ++- .../ds_end_calls_message_bubble.widget.dart | 1 + lib/src/widgets/chat/ds_highlight.dart | 5 +- ...tive_voice_call_message_bubble.widget.dart | 2 +- .../ds_location_message_bubble.widget.dart | 2 +- .../fields/ds_input_container.widget.dart | 10 ++- .../widgets/fields/ds_phone_input.widget.dart | 20 ++++-- .../fields/ds_search_input.widget.dart | 17 +++-- .../fields/ds_select_input.widget.dart | 18 ++++-- .../widgets/fields/ds_text_field.widget.dart | 12 +++- .../fields/ds_text_form_field.widget.dart | 34 +++++++--- .../widgets/tags/ds_input_chip.widget.dart | 8 ++- lib/src/widgets/texts/ds_text.widget.dart | 15 +++-- lib/src/widgets/toast/ds_toast.widget.dart | 7 ++- .../ds_bottomsheet_countries.widget.dart | 21 ++++++- .../utils/ds_circular_progress.widget.dart | 3 +- lib/src/widgets/utils/ds_divider.widget.dart | 13 +++- lib/src/widgets/utils/ds_tab_bar.widget.dart | 4 +- 28 files changed, 240 insertions(+), 88 deletions(-) create mode 100644 devtools_options.yaml create mode 100644 lib/src/services/ds_theme.service.dart diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 00000000..fa0b357c --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/lib/blip_ds.dart b/lib/blip_ds.dart index d350d924..63b1b58f 100644 --- a/lib/blip_ds.dart +++ b/lib/blip_ds.dart @@ -64,6 +64,7 @@ export 'src/services/ds_file.service.dart' show DSFileService; export 'src/services/ds_localization.service.dart' show DSLocalizationService; export 'src/services/ds_media_format.service.dart' show DSMediaFormatService; export 'src/services/ds_security.service.dart' show DSSecurityService; +export 'src/services/ds_theme.service.dart' show DSThemeService; export 'src/services/ds_toast.service.dart' show DSToastService; export 'src/themes/colors/ds_colors.theme.dart' show DSColors; export 'src/themes/colors/ds_dark_colors.theme.dart' show DSDarkColors; diff --git a/lib/src/services/ds_bottom_sheet.service.dart b/lib/src/services/ds_bottom_sheet.service.dart index d0823c0e..35db3303 100644 --- a/lib/src/services/ds_bottom_sheet.service.dart +++ b/lib/src/services/ds_bottom_sheet.service.dart @@ -1,19 +1,23 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import '../themes/colors/ds_colors.theme.dart'; +import '../themes/colors/ds_dark_colors.theme.dart'; class DSBottomSheetService { final BuildContext context; final Widget Function(ScrollController?) builder; final Widget? fixedHeader; final bool hasBottomInsets; + final RxBool darkMode; DSBottomSheetService({ required this.context, required this.builder, this.hasBottomInsets = true, this.fixedHeader, - }); + RxBool? darkMode, + }) : darkMode = darkMode ?? RxBool(false); Widget _buildBottomSheet({ ScrollController? controller, @@ -24,37 +28,39 @@ class DSBottomSheetService { return GestureDetector( onTap: () => FocusManager.instance.primaryFocus?.unfocus(), behavior: HitTestBehavior.translucent, - child: Container( - padding: hasBottomInsets - ? EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom, - ) - : null, - margin: EdgeInsets.only( - top: MediaQueryData.fromView(window).padding.top + 10, - ), - decoration: _border(), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Visibility( - visible: !hideGrabber, - replacement: Container( - decoration: _border(), + child: Obx( + () => Container( + padding: hasBottomInsets + ? EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ) + : null, + margin: EdgeInsets.only( + top: MediaQueryData.fromView(window).padding.top + 10, + ), + decoration: _border(), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Visibility( + visible: !hideGrabber, + replacement: Container( + decoration: _border(), + ), + child: _grabber(), ), - child: _grabber(), - ), - fixedHeader ?? const SizedBox.shrink(), - _buildChild(controller), - ], + fixedHeader ?? const SizedBox.shrink(), + _buildChild(controller), + ], + ), ), ), ); } BoxDecoration _border() { - return const BoxDecoration( - color: DSColors.neutralLightSnow, + return BoxDecoration( + color: darkMode.value ? DSDarkColors.surface3 : DSColors.neutralLightSnow, borderRadius: BorderRadius.only( topLeft: Radius.circular(22.0), topRight: Radius.circular(22.0), @@ -73,8 +79,10 @@ class DSBottomSheetService { Container( height: 4.0, width: 32.0, - decoration: const BoxDecoration( - color: DSColors.neutralMediumWave, + decoration: BoxDecoration( + color: darkMode.value + ? DSColors.neutralLightSnow + : DSColors.neutralMediumWave, borderRadius: BorderRadius.all( Radius.circular(15.0), ), diff --git a/lib/src/services/ds_dialog.service.dart b/lib/src/services/ds_dialog.service.dart index f7754f14..33ff697d 100644 --- a/lib/src/services/ds_dialog.service.dart +++ b/lib/src/services/ds_dialog.service.dart @@ -3,11 +3,13 @@ import 'package:flutter/services.dart'; import '../enums/ds_dialog_type.enum.dart'; import '../themes/colors/ds_colors.theme.dart'; +import '../themes/colors/ds_dark_colors.theme.dart'; import '../themes/icons/ds_icons.dart'; import '../themes/system_overlay/ds_system_overlay.style.dart'; import '../widgets/texts/ds_body_text.widget.dart'; import '../widgets/texts/ds_headline_small_text.widget.dart'; import 'ds_context.service.dart'; +import 'ds_theme.service.dart'; /// A Design System's [Dialog] used to display a dialog box. class DSDialogService { @@ -77,7 +79,9 @@ class DSDialogService { child: Container( constraints: const BoxConstraints(maxWidth: 400.0), decoration: BoxDecoration( - color: DSColors.neutralLightSnow, + color: DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow, borderRadius: const BorderRadius.all(Radius.circular(15.0)), boxShadow: [ BoxShadow( @@ -151,6 +155,7 @@ class DSDialogService { child: DSHeadlineSmallText( title, overflow: TextOverflow.visible, + color: DSColors.neutralDarkCity, ), ), ), @@ -166,6 +171,7 @@ class DSDialogService { child: DSBodyText( text, overflow: TextOverflow.clip, + color: DSThemeService.foregoundColor, ), ); } diff --git a/lib/src/services/ds_theme.service.dart b/lib/src/services/ds_theme.service.dart new file mode 100644 index 00000000..dc00775f --- /dev/null +++ b/lib/src/services/ds_theme.service.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +import '../themes/colors/ds_colors.theme.dart'; + +abstract class DSThemeService { + static ThemeMode _themeMode = ThemeMode.light; + + static setThemeMode(final ThemeMode themeMode) => _themeMode = themeMode; + + static isDarkMode() => _themeMode == ThemeMode.dark; + + static Color get foregoundColor => _themeMode == ThemeMode.dark + ? DSColors.neutralLightSnow + : DSColors.neutralDarkCity; +} diff --git a/lib/src/widgets/buttons/audio/ds_audio_icon_button.widget.dart b/lib/src/widgets/buttons/audio/ds_audio_icon_button.widget.dart index 445d81ba..7b80086a 100644 --- a/lib/src/widgets/buttons/audio/ds_audio_icon_button.widget.dart +++ b/lib/src/widgets/buttons/audio/ds_audio_icon_button.widget.dart @@ -10,12 +10,13 @@ class DSAudioIconButton extends DSTertiaryButton { super.key, super.onPressed, super.isLoading, + Color? iconColor, }) : super( leadingIcon: SvgPicture.asset( 'assets/images/microphone.svg', package: DSUtils.packageName, - colorFilter: const ColorFilter.mode( - DSColors.neutralDarkRooftop, + colorFilter: ColorFilter.mode( + iconColor ?? DSColors.neutralDarkRooftop, BlendMode.srcIn, ), height: 24.0, diff --git a/lib/src/widgets/buttons/audio/ds_audio_resume_button.widget.dart b/lib/src/widgets/buttons/audio/ds_audio_resume_button.widget.dart index b4183cc2..a224d19b 100644 --- a/lib/src/widgets/buttons/audio/ds_audio_resume_button.widget.dart +++ b/lib/src/widgets/buttons/audio/ds_audio_resume_button.widget.dart @@ -1,9 +1,7 @@ import 'package:flutter/painting.dart'; import 'package:flutter_svg/svg.dart'; -import '../../../themes/colors/ds_colors.theme.dart'; -import '../../../utils/ds_utils.util.dart'; -import '../ds_tertiary_button.widget.dart'; +import '../../../../blip_ds.dart'; class DSAudioResumeButton extends DSTertiaryButton { DSAudioResumeButton({ @@ -14,8 +12,10 @@ class DSAudioResumeButton extends DSTertiaryButton { leadingIcon: SvgPicture.asset( 'assets/images/microphone.svg', package: DSUtils.packageName, - colorFilter: const ColorFilter.mode( - DSColors.neutralDarkRooftop, + colorFilter: ColorFilter.mode( + DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.neutralDarkRooftop, BlendMode.srcIn, ), height: 24.0, diff --git a/lib/src/widgets/buttons/ds_attachment_button.widget.dart b/lib/src/widgets/buttons/ds_attachment_button.widget.dart index c402f3e6..7ef708a8 100644 --- a/lib/src/widgets/buttons/ds_attachment_button.widget.dart +++ b/lib/src/widgets/buttons/ds_attachment_button.widget.dart @@ -9,10 +9,11 @@ class DSAttachmentButton extends DSIconButton { super.key, required super.onPressed, super.isLoading, + Color? iconColor, }) : super( - icon: const Icon( + icon: Icon( DSIcons.attach_outline, - color: DSColors.neutralDarkRooftop, + color: iconColor ?? DSColors.neutralDarkRooftop, ), ); } diff --git a/lib/src/widgets/buttons/ds_custom_replies_icon_button.widget.dart b/lib/src/widgets/buttons/ds_custom_replies_icon_button.widget.dart index 138526ae..3d905c78 100644 --- a/lib/src/widgets/buttons/ds_custom_replies_icon_button.widget.dart +++ b/lib/src/widgets/buttons/ds_custom_replies_icon_button.widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import 'ds_icon_button.widget.dart'; @@ -22,9 +23,11 @@ class DSCustomRepliesIconButton extends StatelessWidget { child: DSIconButton( isLoading: isLoading, onPressed: onPressed, - icon: const Icon( + icon: Icon( DSIcons.message_talk_outline, - color: DSColors.neutralDarkRooftop, + color: DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.neutralDarkRooftop, ), ), ); diff --git a/lib/src/widgets/buttons/ds_secondary_button.widget.dart b/lib/src/widgets/buttons/ds_secondary_button.widget.dart index 4af637f3..855a0333 100644 --- a/lib/src/widgets/buttons/ds_secondary_button.widget.dart +++ b/lib/src/widgets/buttons/ds_secondary_button.widget.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; import 'ds_button.widget.dart'; /// A Design System's [ButtonStyleButton] primarily used by secondary actions. @@ -23,10 +25,15 @@ class DSSecondaryButton extends DSButton { Color? foregroundColor, Color? borderColor, }) : super( - backgroundColor: backgroundColor ?? DSColors.neutralLightSnow, + backgroundColor: backgroundColor ?? + (DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow), foregroundColor: foregroundColor ?? (isEnabled - ? DSColors.primaryNight + ? DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.primaryNight : DSColors.neutralMediumElephant), borderColor: borderColor ?? (isEnabled diff --git a/lib/src/widgets/buttons/ds_tertiary_button.widget.dart b/lib/src/widgets/buttons/ds_tertiary_button.widget.dart index 800f2651..70c3ea51 100644 --- a/lib/src/widgets/buttons/ds_tertiary_button.widget.dart +++ b/lib/src/widgets/buttons/ds_tertiary_button.widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; import 'ds_button.widget.dart'; @@ -22,7 +23,11 @@ class DSTertiaryButton extends DSButton { }) : super( backgroundColor: Colors.transparent, foregroundColor: isEnabled - ? DSColors.neutralDarkCity - : DSColors.neutralMediumElephant, + ? DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.neutralDarkCity + : DSThemeService.isDarkMode() + ? DSColors.neutralDarkCity + : DSColors.neutralMediumElephant, ); } diff --git a/lib/src/widgets/chat/calls/ds_end_calls_message_bubble.widget.dart b/lib/src/widgets/chat/calls/ds_end_calls_message_bubble.widget.dart index 6a1fbb90..b6fc85f2 100644 --- a/lib/src/widgets/chat/calls/ds_end_calls_message_bubble.widget.dart +++ b/lib/src/widgets/chat/calls/ds_end_calls_message_bubble.widget.dart @@ -121,6 +121,7 @@ class _DSEndCallsMessageBubbleState extends State { : DSIcons.voip_calling_outline : DSIcons.voip_ended_outline, size: 24.0, + color: DSColors.neutralDarkCity, ), ), ), diff --git a/lib/src/widgets/chat/ds_highlight.dart b/lib/src/widgets/chat/ds_highlight.dart index 706049e0..bbc6bda6 100644 --- a/lib/src/widgets/chat/ds_highlight.dart +++ b/lib/src/widgets/chat/ds_highlight.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../../../blip_ds.dart'; import '../../controllers/chat/ds_highlight.controller.dart'; class DSHighlight extends StatefulWidget { @@ -38,7 +39,9 @@ class _DSTesteState extends State with TickerProviderStateMixin { decoration: DecorationTween( begin: BoxDecoration(), end: BoxDecoration( - color: Colors.black.withValues(alpha: 0.1), + color: DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : Colors.black.withValues(alpha: 0.1), ), ).animate(animationController!), child: widget.child, diff --git a/lib/src/widgets/chat/ds_interactive_voice_call_message_bubble.widget.dart b/lib/src/widgets/chat/ds_interactive_voice_call_message_bubble.widget.dart index 2d24d80e..2d0714c3 100644 --- a/lib/src/widgets/chat/ds_interactive_voice_call_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_interactive_voice_call_message_bubble.widget.dart @@ -53,7 +53,7 @@ class DSInteractiveVoiceCallMessageBubble extends StatelessWidget { content.action?.name == 'voice_call' ? Column( children: [ - const Padding( + Padding( padding: EdgeInsets.symmetric( vertical: 8.0, ), diff --git a/lib/src/widgets/chat/ds_location_message_bubble.widget.dart b/lib/src/widgets/chat/ds_location_message_bubble.widget.dart index 4c8edd72..7d8a17f4 100644 --- a/lib/src/widgets/chat/ds_location_message_bubble.widget.dart +++ b/lib/src/widgets/chat/ds_location_message_bubble.widget.dart @@ -175,7 +175,7 @@ class _DSLocationMessageBubbleState extends State { ), ), ), - const DSDivider() + DSDivider() ], ); } diff --git a/lib/src/widgets/fields/ds_input_container.widget.dart b/lib/src/widgets/fields/ds_input_container.widget.dart index a99c779d..c169fb73 100644 --- a/lib/src/widgets/fields/ds_input_container.widget.dart +++ b/lib/src/widgets/fields/ds_input_container.widget.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import '../../enums/ds_input_container_shape.enum.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; import '../../utils/ds_utils.util.dart'; class DSInputContainer extends StatelessWidget { @@ -45,8 +47,12 @@ class DSInputContainer extends StatelessWidget { : DSColors.neutralLightBox, ), color: isEnabled - ? DSColors.neutralLightSnow - : DSColors.neutralLightWhisper, + ? DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow + : DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : DSColors.neutralLightWhisper, ), child: Container( constraints: BoxConstraints( diff --git a/lib/src/widgets/fields/ds_phone_input.widget.dart b/lib/src/widgets/fields/ds_phone_input.widget.dart index a1f774c9..8065eff7 100644 --- a/lib/src/widgets/fields/ds_phone_input.widget.dart +++ b/lib/src/widgets/fields/ds_phone_input.widget.dart @@ -5,7 +5,9 @@ import 'package:mask_text_input_formatter/mask_text_input_formatter.dart'; import '../../extensions/ds_localization.extension.dart'; import '../../models/ds_country.model.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../themes/texts/styles/ds_body_text_style.theme.dart'; import '../../themes/texts/styles/ds_text_style.theme.dart'; @@ -95,7 +97,9 @@ class _DSPhoneInputState extends State { () => Container( padding: const EdgeInsets.fromLTRB(12.0, 0.0, 4.0, 0.0), decoration: BoxDecoration( - color: DSColors.neutralLightSnow, + color: DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow, border: Border.all(color: _borderColor.value), borderRadius: BorderRadius.circular(8.0), ), @@ -111,10 +115,12 @@ class _DSPhoneInputState extends State { ), child: DSText( widget.labelText, - style: const DSTextStyle( + style: DSTextStyle( fontSize: 9.0, fontWeight: DSFontWeights.bold, - color: DSColors.neutralMediumCloud, + color: DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.neutralMediumCloud, ), height: 0.0, ), @@ -202,9 +208,9 @@ class _DSPhoneInputState extends State { widget.onChanged!(value); } }, - style: const TextStyle( + style: TextStyle( fontSize: 16.0, - color: DSColors.neutralDarkCity, + color: DSThemeService.foregoundColor, fontFamily: DSFontFamilies.nunitoSans, ), keyboardType: TextInputType.number, @@ -267,7 +273,9 @@ class _DSPhoneInputState extends State { } else if (_focusNode.hasFocus && widget.shouldFocus) { return DSColors.primaryNight; } else { - return DSColors.neutralMediumWave; + return DSThemeService.isDarkMode() + ? DSDarkColors.surface0 + : DSColors.neutralMediumWave; } } } diff --git a/lib/src/widgets/fields/ds_search_input.widget.dart b/lib/src/widgets/fields/ds_search_input.widget.dart index 2eb6f984..58b69b28 100644 --- a/lib/src/widgets/fields/ds_search_input.widget.dart +++ b/lib/src/widgets/fields/ds_search_input.widget.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../themes/texts/styles/ds_body_text_style.theme.dart'; @@ -38,7 +40,10 @@ class DSSearchInput extends StatelessWidget { focusNode: focusNode, controller: controller, onChanged: onSearch, - style: const DSBodyTextStyle(color: DSColors.neutralDarkCity), + style: DSBodyTextStyle( + color: DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.neutralDarkCity), autofocus: false, decoration: InputDecoration( suffixIcon: Visibility( @@ -52,7 +57,9 @@ class DSSearchInput extends StatelessWidget { ), ), ), - fillColor: DSColors.neutralLightSnow, + fillColor: DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow, prefixIconConstraints: const BoxConstraints( minWidth: 25.0, minHeight: 25.0, @@ -98,8 +105,10 @@ class DSSearchInput extends StatelessWidget { OutlineInputBorder _getBorder() => OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), - borderSide: const BorderSide( - color: DSColors.neutralMediumWave, + borderSide: BorderSide( + color: DSThemeService.isDarkMode() + ? DSDarkColors.surface0 + : DSColors.neutralMediumWave, width: 1.0, ), ); diff --git a/lib/src/widgets/fields/ds_select_input.widget.dart b/lib/src/widgets/fields/ds_select_input.widget.dart index ad79f143..6f8049d8 100644 --- a/lib/src/widgets/fields/ds_select_input.widget.dart +++ b/lib/src/widgets/fields/ds_select_input.widget.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../themes/texts/styles/ds_body_text_style.theme.dart'; @@ -49,7 +51,11 @@ class DSSelectInput extends StatelessWidget { focusNode: focusNode, controller: controller, onChanged: onChanged, - style: const DSBodyTextStyle(color: DSColors.neutralDarkCity), + style: DSBodyTextStyle( + color: DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.neutralDarkCity, + ), autofocus: false, decoration: InputDecoration( suffixIcon: Visibility( @@ -59,7 +65,9 @@ class DSSelectInput extends StatelessWidget { color: DSColors.neutralMediumCloud, ), ), - fillColor: DSColors.neutralLightSnow, + fillColor: DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow, contentPadding: const EdgeInsets.all(10.0), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), @@ -70,8 +78,10 @@ class DSSelectInput extends StatelessWidget { ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), - borderSide: const BorderSide( - color: DSColors.neutralMediumWave, + borderSide: BorderSide( + color: DSThemeService.isDarkMode() + ? DSDarkColors.surface0 + : DSColors.neutralMediumWave, width: 1.0, ), ), diff --git a/lib/src/widgets/fields/ds_text_field.widget.dart b/lib/src/widgets/fields/ds_text_field.widget.dart index 88ec17f2..a5247b45 100644 --- a/lib/src/widgets/fields/ds_text_field.widget.dart +++ b/lib/src/widgets/fields/ds_text_field.widget.dart @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../enums/ds_input_container_shape.enum.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../themes/texts/styles/ds_body_text_style.theme.dart'; import '../../utils/ds_utils.util.dart'; @@ -128,7 +130,7 @@ class _DSTextFieldState extends State { scrollController: _scrollController, enabled: widget.isEnabled, obscureText: widget.obscureText, - style: const DSBodyTextStyle(), + style: DSBodyTextStyle(color: DSThemeService.foregoundColor), cursorColor: DSColors.primaryMain, cursorHeight: 20.0, textCapitalization: widget.textCapitalization, @@ -138,6 +140,14 @@ class _DSTextFieldState extends State { onTap: widget.onTap, onTapOutside: widget.onTapOutside, decoration: InputDecoration( + fillColor: widget.isEnabled + ? DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow + : DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : DSColors.neutralLightWhisper, + filled: true, isDense: true, contentPadding: EdgeInsets.zero, border: InputBorder.none, diff --git a/lib/src/widgets/fields/ds_text_form_field.widget.dart b/lib/src/widgets/fields/ds_text_form_field.widget.dart index c69ee781..c5dd483b 100644 --- a/lib/src/widgets/fields/ds_text_form_field.widget.dart +++ b/lib/src/widgets/fields/ds_text_form_field.widget.dart @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../themes/texts/styles/ds_body_text_style.theme.dart'; import '../../themes/texts/styles/ds_caption_small_text_style.theme.dart'; @@ -64,8 +66,12 @@ class _DSTextFormFieldState extends State { padding: const EdgeInsets.fromLTRB(12.0, 6.0, 4.0, 6.0), decoration: BoxDecoration( color: widget.isEnabled - ? DSColors.neutralLightSnow - : DSColors.neutralLightWhisper, + ? DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow + : DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : DSColors.neutralLightWhisper, border: Border.all(color: _borderColor.value), borderRadius: BorderRadius.circular(8), ), @@ -76,7 +82,9 @@ class _DSTextFormFieldState extends State { onChanged: widget.onChanged, style: DSBodyTextStyle( color: widget.isEnabled - ? DSColors.neutralDarkCity + ? DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.neutralDarkCity : DSColors.neutralMediumSilver, ), autofocus: false, @@ -84,15 +92,21 @@ class _DSTextFormFieldState extends State { inputFormatters: widget.inputFormatters, decoration: InputDecoration( fillColor: widget.isEnabled - ? DSColors.neutralLightSnow - : DSColors.neutralLightWhisper, + ? DSThemeService.isDarkMode() + ? DSDarkColors.surface3 + : DSColors.neutralLightSnow + : DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : DSColors.neutralLightWhisper, contentPadding: EdgeInsets.zero, border: InputBorder.none, labelText: widget.labelText, labelStyle: DSCaptionSmallTextStyle( fontWeight: DSFontWeights.bold, color: widget.isEnabled - ? DSColors.neutralMediumCloud + ? DSThemeService.isDarkMode() + ? DSColors.neutralLightSnow + : DSColors.neutralMediumCloud : DSColors.neutralMediumSilver, ), filled: true, @@ -134,9 +148,13 @@ class _DSTextFormFieldState extends State { } else if (_focusNode.hasFocus) { return DSColors.primaryNight; } else if (widget.isEnabled) { - return DSColors.neutralMediumWave; + return DSThemeService.isDarkMode() + ? DSDarkColors.surface0 + : DSColors.neutralMediumWave; } else { - return DSColors.neutralLightBox; + return DSThemeService.isDarkMode() + ? DSDarkColors.surface0 + : DSColors.neutralLightBox; } } } diff --git a/lib/src/widgets/tags/ds_input_chip.widget.dart b/lib/src/widgets/tags/ds_input_chip.widget.dart index 1c1739a8..e702d201 100644 --- a/lib/src/widgets/tags/ds_input_chip.widget.dart +++ b/lib/src/widgets/tags/ds_input_chip.widget.dart @@ -7,6 +7,7 @@ import '/src/themes/texts/styles/ds_body_text_style.theme.dart'; import '/src/widgets/tags/tag_editor/tag_editor.dart'; import '/src/widgets/texts/ds_headline_small_text.widget.dart'; import '/src/widgets/utils/ds_chip.widget.dart'; +import '../../services/ds_theme.service.dart'; import '../buttons/ds_icon_button.widget.dart'; class DSInputChip extends StatefulWidget { @@ -62,7 +63,7 @@ class _DSInputChipState extends State { borderRadius: 8.0, enableBorderColor: DSColors.neutralMediumWave, focusedBorderColor: DSColors.primaryMain, - textStyle: const DSBodyTextStyle(), + textStyle: DSBodyTextStyle(color: DSThemeService.foregoundColor), controller: widget.controller, length: widget.values.length, delimiters: const [], @@ -97,7 +98,10 @@ class _DSInputChipState extends State { borderRadius: const BorderRadius.all( Radius.circular(16.0), ), - text: DSHeadlineSmallText(widget.values[index]), + text: DSHeadlineSmallText( + widget.values[index], + color: DSColors.neutralDarkCity, + ), background: DSColors.primaryLight, trailingIcon: SizedBox( child: DSIconButton( diff --git a/lib/src/widgets/texts/ds_text.widget.dart b/lib/src/widgets/texts/ds_text.widget.dart index c33e468d..3a7e98fb 100644 --- a/lib/src/widgets/texts/ds_text.widget.dart +++ b/lib/src/widgets/texts/ds_text.widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../../services/ds_theme.service.dart'; import '../../services/ds_security.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../../themes/texts/utils/ds_font_weights.theme.dart'; @@ -23,13 +24,13 @@ class DSText extends StatelessWidget { final double? height; /// Creates a Design System's [Text]. - const DSText( + DSText( this.text, { required this.style, super.key, this.fontWeight = DSFontWeights.regular, this.fontStyle = FontStyle.normal, - this.color = DSColors.neutralDarkCity, + Color? color, this.linkColor = DSColors.primaryNight, this.overflow = TextOverflow.ellipsis, this.decoration, @@ -38,15 +39,16 @@ class DSText extends StatelessWidget { this.shouldLinkify = true, this.isSelectable = false, this.height, - }) : span = null; + }) : color = DSThemeService.foregoundColor, + span = null; - const DSText.rich( + DSText.rich( this.span, { required this.style, super.key, this.fontWeight = DSFontWeights.regular, this.fontStyle = FontStyle.normal, - this.color = DSColors.neutralDarkCity, + Color? color, this.linkColor = DSColors.primaryNight, this.overflow = TextOverflow.ellipsis, this.decoration, @@ -55,7 +57,8 @@ class DSText extends StatelessWidget { this.shouldLinkify = true, this.isSelectable = false, this.height, - }) : text = null; + }) : color = DSThemeService.foregoundColor, + text = null; @override Widget build(BuildContext context) => diff --git a/lib/src/widgets/toast/ds_toast.widget.dart b/lib/src/widgets/toast/ds_toast.widget.dart index e6b79f8b..42244403 100644 --- a/lib/src/widgets/toast/ds_toast.widget.dart +++ b/lib/src/widgets/toast/ds_toast.widget.dart @@ -162,11 +162,13 @@ class _DSToastState extends State with AutomaticKeepAliveClientMixin { DSHeadlineSmallText( props.title, overflow: TextOverflow.visible, + color: DSColors.neutralDarkCity, ), if (props.message?.isNotEmpty ?? false) DSBodyText( props.message, overflow: TextOverflow.visible, + color: DSColors.neutralDarkCity, ), ], ), @@ -175,7 +177,10 @@ class _DSToastState extends State with AutomaticKeepAliveClientMixin { if (props.actionType == DSToastActionType.icon) DSIconButton( size: 40.0, - icon: const Icon(DSIcons.close_outline), + icon: Icon( + DSIcons.close_outline, + color: DSColors.neutralDarkCity, + ), onPressed: () => state!(_closeToast), ), ], diff --git a/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart b/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart index d3dd56a3..056411be 100644 --- a/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart +++ b/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart @@ -7,7 +7,9 @@ import '../../models/ds_country.model.dart'; import '../../services/ds_bottom_sheet.service.dart'; import '../../services/ds_context.service.dart'; import '../../services/ds_navigation.service.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../utils/ds_utils.util.dart'; import '../buttons/ds_icon_button.widget.dart'; @@ -32,6 +34,7 @@ abstract class DSBottomSheetCountries { static Future _bottomSheetCountries() { return DSBottomSheetService( + darkMode: DSThemeService.isDarkMode() ? RxBool(true) : RxBool(false), fixedHeader: Column( children: [ Padding( @@ -58,7 +61,11 @@ abstract class DSBottomSheetCountries { ), ), ), - const DSDivider(), + DSDivider( + color: DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : DSColors.neutralMediumWave, + ), Padding( padding: const EdgeInsets.symmetric( horizontal: 16.0, @@ -75,7 +82,11 @@ abstract class DSBottomSheetCountries { ), ), ), - const DSDivider(), + DSDivider( + color: DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : DSColors.neutralMediumWave, + ), ], ), context: DSContextService.context!, @@ -130,7 +141,11 @@ abstract class DSBottomSheetCountries { ), groupValue: selectedCountry.value, ), - const DSDivider(), + DSDivider( + color: DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : DSColors.neutralMediumWave, + ), ], ), ), diff --git a/lib/src/widgets/utils/ds_circular_progress.widget.dart b/lib/src/widgets/utils/ds_circular_progress.widget.dart index 68868768..536d749b 100644 --- a/lib/src/widgets/utils/ds_circular_progress.widget.dart +++ b/lib/src/widgets/utils/ds_circular_progress.widget.dart @@ -2,6 +2,7 @@ import 'package:file_sizes/file_sizes.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; import '../texts/ds_caption_small_text.widget.dart'; @@ -45,7 +46,7 @@ class DSCircularProgress extends StatelessWidget { if (currentProgress.value > 0 && maximumProgress.value > 0) DSCaptionSmallText( _buildProgress(), - color: foregroundColor ?? DSColors.neutralDarkCity, + color: foregroundColor ?? DSThemeService.foregoundColor, ) ], ), diff --git a/lib/src/widgets/utils/ds_divider.widget.dart b/lib/src/widgets/utils/ds_divider.widget.dart index 3a8146e3..ded951ad 100644 --- a/lib/src/widgets/utils/ds_divider.widget.dart +++ b/lib/src/widgets/utils/ds_divider.widget.dart @@ -1,12 +1,19 @@ import 'package:flutter/material.dart'; +import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; class DSDivider extends Divider { - const DSDivider({ + DSDivider({ super.key, super.thickness = 1.0, super.height = 1.0, - super.color = DSColors.neutralMediumWave, - }); + Color? color, + }) : super( + color: color ?? + (DSThemeService.isDarkMode() + ? DSDarkColors.surface1 + : DSColors.neutralMediumWave), + ); } diff --git a/lib/src/widgets/utils/ds_tab_bar.widget.dart b/lib/src/widgets/utils/ds_tab_bar.widget.dart index 76727e26..90e9de05 100644 --- a/lib/src/widgets/utils/ds_tab_bar.widget.dart +++ b/lib/src/widgets/utils/ds_tab_bar.widget.dart @@ -8,12 +8,14 @@ class DSTabBar extends StatelessWidget { final TabController? controller; final Function(int)? onTap; final List tabs; + final Color? dividerColor; const DSTabBar({ required this.tabs, super.key, this.controller, this.onTap, + this.dividerColor, }); @override @@ -27,7 +29,7 @@ class DSTabBar extends StatelessWidget { unselectedLabelStyle: const DSBodyTextStyle( color: DSColors.neutralDarkCity, ), - dividerColor: DSColors.neutralMediumWave, + dividerColor: dividerColor ?? DSColors.neutralMediumWave, indicatorSize: TabBarIndicatorSize.tab, indicatorWeight: 0.0, indicator: const UnderlineTabIndicator( From 925c73bbd10b81cbe516e67144701cfcaf4095fc Mon Sep 17 00:00:00 2001 From: Andre Rossi Date: Mon, 3 Feb 2025 11:04:27 -0300 Subject: [PATCH 2/6] feat: fix color --- lib/src/widgets/fields/ds_search_input.widget.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/widgets/fields/ds_search_input.widget.dart b/lib/src/widgets/fields/ds_search_input.widget.dart index 58b69b28..aba7a61f 100644 --- a/lib/src/widgets/fields/ds_search_input.widget.dart +++ b/lib/src/widgets/fields/ds_search_input.widget.dart @@ -36,6 +36,7 @@ class DSSearchInput extends StatelessWidget { return SizedBox( height: 44.0, child: TextField( + cursorColor: DSColors.primaryMain, enabled: enabled ?? true, focusNode: focusNode, controller: controller, From 1282c45005230ee4f70a3365715a5bf2659a05e0 Mon Sep 17 00:00:00 2001 From: Andre Rossi Date: Mon, 3 Feb 2025 11:50:18 -0300 Subject: [PATCH 3/6] feat: fix imports --- .../audio/ds_audio_resume_button.widget.dart | 5 ++++- lib/src/widgets/chat/ds_highlight.dart | 3 ++- .../widgets/fields/ds_phone_input.widget.dart | 12 +++++------- .../ds_bottomsheet_countries.widget.dart | 19 +++---------------- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/lib/src/widgets/buttons/audio/ds_audio_resume_button.widget.dart b/lib/src/widgets/buttons/audio/ds_audio_resume_button.widget.dart index a224d19b..740c4924 100644 --- a/lib/src/widgets/buttons/audio/ds_audio_resume_button.widget.dart +++ b/lib/src/widgets/buttons/audio/ds_audio_resume_button.widget.dart @@ -1,7 +1,10 @@ import 'package:flutter/painting.dart'; import 'package:flutter_svg/svg.dart'; -import '../../../../blip_ds.dart'; +import '../../../services/ds_theme.service.dart'; +import '../../../themes/colors/ds_colors.theme.dart'; +import '../../../utils/ds_utils.util.dart'; +import '../ds_tertiary_button.widget.dart'; class DSAudioResumeButton extends DSTertiaryButton { DSAudioResumeButton({ diff --git a/lib/src/widgets/chat/ds_highlight.dart b/lib/src/widgets/chat/ds_highlight.dart index bbc6bda6..8057eb69 100644 --- a/lib/src/widgets/chat/ds_highlight.dart +++ b/lib/src/widgets/chat/ds_highlight.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; -import '../../../blip_ds.dart'; import '../../controllers/chat/ds_highlight.controller.dart'; +import '../../services/ds_theme.service.dart'; +import '../../themes/colors/ds_dark_colors.theme.dart'; class DSHighlight extends StatefulWidget { final Widget child; diff --git a/lib/src/widgets/fields/ds_phone_input.widget.dart b/lib/src/widgets/fields/ds_phone_input.widget.dart index 8065eff7..d058c263 100644 --- a/lib/src/widgets/fields/ds_phone_input.widget.dart +++ b/lib/src/widgets/fields/ds_phone_input.widget.dart @@ -128,6 +128,7 @@ class _DSPhoneInputState extends State { ), Row( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.only(right: 4.0), @@ -179,13 +180,10 @@ class _DSPhoneInputState extends State { ), ), ), - Padding( - padding: const EdgeInsets.only(top: 3.0), - child: Obx( - () => DSBodyText( - _dropdownValue.value.code, - color: DSColors.neutralMediumElephant, - ), + Obx( + () => DSBodyText( + _dropdownValue.value.code, + color: DSColors.neutralMediumElephant, ), ), ], diff --git a/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart b/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart index 056411be..ac50c16d 100644 --- a/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart +++ b/lib/src/widgets/utils/ds_bottomsheet_countries.widget.dart @@ -9,7 +9,6 @@ import '../../services/ds_context.service.dart'; import '../../services/ds_navigation.service.dart'; import '../../services/ds_theme.service.dart'; import '../../themes/colors/ds_colors.theme.dart'; -import '../../themes/colors/ds_dark_colors.theme.dart'; import '../../themes/icons/ds_icons.dart'; import '../../utils/ds_utils.util.dart'; import '../buttons/ds_icon_button.widget.dart'; @@ -61,11 +60,7 @@ abstract class DSBottomSheetCountries { ), ), ), - DSDivider( - color: DSThemeService.isDarkMode() - ? DSDarkColors.surface1 - : DSColors.neutralMediumWave, - ), + DSDivider(), Padding( padding: const EdgeInsets.symmetric( horizontal: 16.0, @@ -82,11 +77,7 @@ abstract class DSBottomSheetCountries { ), ), ), - DSDivider( - color: DSThemeService.isDarkMode() - ? DSDarkColors.surface1 - : DSColors.neutralMediumWave, - ), + DSDivider(), ], ), context: DSContextService.context!, @@ -141,11 +132,7 @@ abstract class DSBottomSheetCountries { ), groupValue: selectedCountry.value, ), - DSDivider( - color: DSThemeService.isDarkMode() - ? DSDarkColors.surface1 - : DSColors.neutralMediumWave, - ), + DSDivider(), ], ), ), From a40b81a8484e3549eafbb950e4b091bf0123be25 Mon Sep 17 00:00:00 2001 From: Marcelo Amaro Date: Tue, 4 Feb 2025 08:36:39 -0300 Subject: [PATCH 4/6] feat: add sticker media support --- lib/src/models/ds_media_link.model.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/src/models/ds_media_link.model.dart b/lib/src/models/ds_media_link.model.dart index 7d19c313..4bac9ded 100644 --- a/lib/src/models/ds_media_link.model.dart +++ b/lib/src/models/ds_media_link.model.dart @@ -21,11 +21,18 @@ class DSMediaLink { DSMediaLink.fromJson(Map json) : uri = json['uri'], - type = json['type'], + type = _formatMimeType( + type: json['type'], + ), title = json['title'], text = json['text'], aspectRatio = json['aspectRatio'], size = json['size'], authorizationRealm = json['authorizationRealm'], previewUri = json['previewUri']; + + static String _formatMimeType({ + required final String? type, + }) => + type?.replaceFirst('sticker/', 'image/') ?? ''; } From cef9db9999a54d37700d8fe7839d06e0242d66f5 Mon Sep 17 00:00:00 2001 From: Marcelo Amaro Date: Tue, 4 Feb 2025 08:45:49 -0300 Subject: [PATCH 5/6] feat: transform media link mime type to lower case --- lib/src/models/ds_media_link.model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/models/ds_media_link.model.dart b/lib/src/models/ds_media_link.model.dart index 4bac9ded..d6d91cd9 100644 --- a/lib/src/models/ds_media_link.model.dart +++ b/lib/src/models/ds_media_link.model.dart @@ -34,5 +34,5 @@ class DSMediaLink { static String _formatMimeType({ required final String? type, }) => - type?.replaceFirst('sticker/', 'image/') ?? ''; + type?.toLowerCase().replaceFirst('sticker/', 'image/') ?? ''; } From 963b042407c0eb80195817109f88d36d96d93b01 Mon Sep 17 00:00:00 2001 From: Andre Rossi Date: Wed, 5 Feb 2025 10:12:34 -0300 Subject: [PATCH 6/6] chore: upgrade version --- CHANGELOG.md | 4 ++++ pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d105b52b..0eba164f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.4 + +- Added support to dark mode. + ## 0.3.3 - [DSTabBar] Added new widget based on Material TabBar. diff --git a/pubspec.yaml b/pubspec.yaml index 093246cb..0ce168e3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: blip_ds description: Blip Design System for Flutter. -version: 0.3.3 +version: 0.3.4 homepage: https://github.com/takenet/blip-ds-flutter#readme repository: https://github.com/takenet/blip-ds-flutter