diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c5f9dfb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# Contributing to Suggest a Feature + +This document provides guidelines and information for developers working on this package. + +## Working with SVG Assets + +This package uses the `vector_graphics` package for rendering SVG icons. Because `vector_graphics` transformers don't work across package boundaries, we pre-compile all SVG assets into `.vec` format. + +### Adding or Modifying SVG Assets + +When you add new SVG files or modify existing ones in the `assets/` directory, you must re-compile them: + +**Step 1:** Add or update your SVG file in `assets/` + +**Step 2:** Run the compilation script: +```bash +dart run scripts/compile_svgs.dart +``` + +**Step 3:** Reference the compiled asset in code: +```dart +// In assets_strings.dart +static const String myIcon = 'assets/compiled/my_icon.svg.vec'; +``` + +### Why Pre-compilation is Required + +The `vector_graphics_compiler` package uses asset transformers that only work in application projects, not in library packages. By pre-compiling our SVG assets during development, we ensure that: +- Package users only need the `vector_graphics` runtime dependency +- Users don't need to add `vector_graphics_compiler` or configure transformers +- Assets are optimized for faster rendering + +**Important:** Always commit both the source `.svg` files and the compiled `.vec` files to the repository. diff --git a/assets/compiled/add_photo_icon.svg.vec b/assets/compiled/add_photo_icon.svg.vec new file mode 100644 index 0000000..1adccd3 Binary files /dev/null and b/assets/compiled/add_photo_icon.svg.vec differ diff --git a/assets/compiled/arrow_down_icon.svg.vec b/assets/compiled/arrow_down_icon.svg.vec new file mode 100644 index 0000000..b504258 Binary files /dev/null and b/assets/compiled/arrow_down_icon.svg.vec differ diff --git a/assets/compiled/arrow_left_icon.svg.vec b/assets/compiled/arrow_left_icon.svg.vec new file mode 100644 index 0000000..3b9450a Binary files /dev/null and b/assets/compiled/arrow_left_icon.svg.vec differ diff --git a/assets/compiled/arrow_up_suggestion.svg.vec b/assets/compiled/arrow_up_suggestion.svg.vec new file mode 100644 index 0000000..40c9988 Binary files /dev/null and b/assets/compiled/arrow_up_suggestion.svg.vec differ diff --git a/assets/compiled/check_icon.svg.vec b/assets/compiled/check_icon.svg.vec new file mode 100644 index 0000000..bf06db7 Binary files /dev/null and b/assets/compiled/check_icon.svg.vec differ diff --git a/assets/compiled/close_icon.svg.vec b/assets/compiled/close_icon.svg.vec new file mode 100644 index 0000000..05e9fb1 Binary files /dev/null and b/assets/compiled/close_icon.svg.vec differ diff --git a/assets/compiled/delete_icon.svg.vec b/assets/compiled/delete_icon.svg.vec new file mode 100644 index 0000000..496cd36 Binary files /dev/null and b/assets/compiled/delete_icon.svg.vec differ diff --git a/assets/compiled/download_icon.svg.vec b/assets/compiled/download_icon.svg.vec new file mode 100644 index 0000000..029377f Binary files /dev/null and b/assets/compiled/download_icon.svg.vec differ diff --git a/assets/compiled/notifications_icon.svg.vec b/assets/compiled/notifications_icon.svg.vec new file mode 100644 index 0000000..436151d Binary files /dev/null and b/assets/compiled/notifications_icon.svg.vec differ diff --git a/assets/compiled/pen_icon.svg.vec b/assets/compiled/pen_icon.svg.vec new file mode 100644 index 0000000..5d3e625 Binary files /dev/null and b/assets/compiled/pen_icon.svg.vec differ diff --git a/assets/compiled/plus_icon_thick.svg.vec b/assets/compiled/plus_icon_thick.svg.vec new file mode 100644 index 0000000..07a634d Binary files /dev/null and b/assets/compiled/plus_icon_thick.svg.vec differ diff --git a/assets/compiled/plus_icon_thin.svg.vec b/assets/compiled/plus_icon_thin.svg.vec new file mode 100644 index 0000000..c3fcf6e Binary files /dev/null and b/assets/compiled/plus_icon_thin.svg.vec differ diff --git a/assets/compiled/profile_icon.svg.vec b/assets/compiled/profile_icon.svg.vec new file mode 100644 index 0000000..695b8ac Binary files /dev/null and b/assets/compiled/profile_icon.svg.vec differ diff --git a/assets/compiled/suggestions_completed.svg.vec b/assets/compiled/suggestions_completed.svg.vec new file mode 100644 index 0000000..52b054c Binary files /dev/null and b/assets/compiled/suggestions_completed.svg.vec differ diff --git a/assets/compiled/suggestions_declined.svg.vec b/assets/compiled/suggestions_declined.svg.vec new file mode 100644 index 0000000..8d6da2b Binary files /dev/null and b/assets/compiled/suggestions_declined.svg.vec differ diff --git a/assets/compiled/suggestions_duplicated.svg.vec b/assets/compiled/suggestions_duplicated.svg.vec new file mode 100644 index 0000000..bb85f77 Binary files /dev/null and b/assets/compiled/suggestions_duplicated.svg.vec differ diff --git a/assets/compiled/suggestions_in_progress.svg.vec b/assets/compiled/suggestions_in_progress.svg.vec new file mode 100644 index 0000000..fa2785e Binary files /dev/null and b/assets/compiled/suggestions_in_progress.svg.vec differ diff --git a/assets/compiled/suggestions_requests.svg.vec b/assets/compiled/suggestions_requests.svg.vec new file mode 100644 index 0000000..c607242 Binary files /dev/null and b/assets/compiled/suggestions_requests.svg.vec differ diff --git a/example/pubspec.lock b/example/pubspec.lock index 5365258..691b9de 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,14 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" async: dependency: transitive description: @@ -86,14 +78,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" - flutter_svg: - dependency: transitive - description: - name: flutter_svg - sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845 - url: "https://pub.dev" - source: hosted - version: "2.2.0" flutter_test: dependency: "direct dev" description: flutter @@ -187,22 +171,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" - url: "https://pub.dev" - source: hosted - version: "6.1.0" sky_engine: dependency: transitive description: flutter @@ -287,14 +255,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331" - url: "https://pub.dev" - source: hosted - version: "1.1.17" vector_math: dependency: transitive description: @@ -327,14 +287,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.5" - xml: - dependency: transitive - description: - name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 - url: "https://pub.dev" - source: hosted - version: "6.5.0" sdks: dart: ">=3.7.0-0 <4.0.0" flutter: ">=3.27.0" diff --git a/lib/src/presentation/pages/suggestion/create_edit/create_edit_suggestion_bottom_sheet.dart b/lib/src/presentation/pages/suggestion/create_edit/create_edit_suggestion_bottom_sheet.dart index 728e11f..0a5a241 100644 --- a/lib/src/presentation/pages/suggestion/create_edit/create_edit_suggestion_bottom_sheet.dart +++ b/lib/src/presentation/pages/suggestion/create_edit/create_edit_suggestion_bottom_sheet.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:suggest_a_feature/src/domain/entities/suggestion.dart'; import 'package:suggest_a_feature/src/presentation/di/injector.dart'; import 'package:suggest_a_feature/src/presentation/localization/localization_extensions.dart'; @@ -15,6 +14,7 @@ import 'package:suggest_a_feature/src/presentation/pages/widgets/network_image.d import 'package:suggest_a_feature/src/presentation/pages/widgets/photo_view.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/small_photo_preview.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/state_listener.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_labels.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_switch.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_text_field.dart'; @@ -256,14 +256,10 @@ class _LabelItems extends StatelessWidget { ), trailing: labels.isNotEmpty ? SuggestionLabels(labels: labels) - : SvgPicture.asset( + : SuggestionsIcon( AssetStrings.plusIconThickImage, - package: AssetStrings.packageName, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), - height: Dimensions.defaultSize, + color: context.theme.colorScheme.onSurface, + size: Dimensions.defaultSize, ), onClick: () => changeLabelsBottomSheetStatus(true), verticalPadding: Dimensions.marginDefault, @@ -521,14 +517,10 @@ class _AddButton extends StatelessWidget { context.theme.colorScheme.onSurface, ), ) - : SvgPicture.asset( + : SuggestionsIcon( AssetStrings.plusIconThickImage, - package: AssetStrings.packageName, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), - height: isSmall ? Dimensions.smallSize : Dimensions.defaultSize, + color: context.theme.colorScheme.onSurface, + size: isSmall ? Dimensions.smallSize : Dimensions.defaultSize, ), onClick: onUploadPhotos, verticalPadding: Dimensions.marginDefault, diff --git a/lib/src/presentation/pages/suggestion/suggestion_page.dart b/lib/src/presentation/pages/suggestion/suggestion_page.dart index 3b4dd0a..22590b1 100644 --- a/lib/src/presentation/pages/suggestion/suggestion_page.dart +++ b/lib/src/presentation/pages/suggestion/suggestion_page.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:suggest_a_feature/src/domain/entities/admin_settings.dart'; import 'package:suggest_a_feature/src/domain/entities/comment.dart'; import 'package:suggest_a_feature/src/domain/entities/suggestion.dart'; @@ -20,6 +19,7 @@ import 'package:suggest_a_feature/src/presentation/pages/widgets/icon_button.dar import 'package:suggest_a_feature/src/presentation/pages/widgets/network_image.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/photo_view.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/state_listener.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_labels.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/votes_counter.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; @@ -834,13 +834,9 @@ class _UpvoteButton extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - SvgPicture.asset( + SuggestionsIcon( AssetStrings.suggestionsUpvoteArrow, - package: AssetStrings.packageName, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.onPrimary, - BlendMode.srcIn, - ), + color: context.theme.colorScheme.onPrimary, ), const SizedBox(width: Dimensions.marginSmall), Flexible( diff --git a/lib/src/presentation/pages/suggestions/widgets/list_description.dart b/lib/src/presentation/pages/suggestions/widgets/list_description.dart index 93c937f..edff41c 100644 --- a/lib/src/presentation/pages/suggestions/widgets/list_description.dart +++ b/lib/src/presentation/pages/suggestions/widgets/list_description.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:suggest_a_feature/src/presentation/localization/localization_extensions.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; import 'package:suggest_a_feature/suggest_a_feature.dart'; @@ -111,13 +111,9 @@ class ListDescription extends StatelessWidget { overflow: TextOverflow.ellipsis, ), ), - SvgPicture.asset( + SuggestionsIcon( AssetStrings.arrowDownIcon, - package: AssetStrings.packageName, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.primary, - BlendMode.srcIn, - ), + color: context.theme.colorScheme.primary, ), ], ), diff --git a/lib/src/presentation/pages/suggestions/widgets/suggestions_tab_bar.dart b/lib/src/presentation/pages/suggestions/widgets/suggestions_tab_bar.dart index f6d5246..fc1d659 100644 --- a/lib/src/presentation/pages/suggestions/widgets/suggestions_tab_bar.dart +++ b/lib/src/presentation/pages/suggestions/widgets/suggestions_tab_bar.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:suggest_a_feature/src/presentation/localization/localization_extensions.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; import 'package:suggest_a_feature/suggest_a_feature.dart'; @@ -109,15 +109,11 @@ class _TabIcon extends StatelessWidget { @override Widget build(BuildContext context) { return SizedBox( - child: SvgPicture.asset( + child: SuggestionsIcon( iconPath, - package: AssetStrings.packageName, - colorFilter: ColorFilter.mode( - isActive - ? context.theme.colorScheme.onSurface - : context.theme.colorScheme.onSurfaceVariant, - BlendMode.srcIn, - ), + color: isActive + ? context.theme.colorScheme.onSurface + : context.theme.colorScheme.onSurfaceVariant, ), ); } diff --git a/lib/src/presentation/pages/widgets/add_event_photo_button.dart b/lib/src/presentation/pages/widgets/add_event_photo_button.dart index 8be09d6..9f52eba 100644 --- a/lib/src/presentation/pages/widgets/add_event_photo_button.dart +++ b/lib/src/presentation/pages/widgets/add_event_photo_button.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:suggest_a_feature/src/presentation/localization/localization_extensions.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/dotted_border.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; @@ -59,14 +59,10 @@ class _AddButton extends StatelessWidget { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - SvgPicture.asset( + SuggestionsIcon( AssetStrings.addPhotoButton, - package: AssetStrings.packageName, - height: Dimensions.defaultSize, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), + color: context.theme.colorScheme.onSurface, + size: Dimensions.defaultSize, ), Padding( padding: const EdgeInsets.only(top: Dimensions.marginSmall), diff --git a/lib/src/presentation/pages/widgets/avatar_widget.dart b/lib/src/presentation/pages/widgets/avatar_widget.dart index 9081e09..7f23319 100644 --- a/lib/src/presentation/pages/widgets/avatar_widget.dart +++ b/lib/src/presentation/pages/widgets/avatar_widget.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/network_image.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; @@ -34,13 +34,9 @@ class AvatarWidget extends StatelessWidget { ? SuggestionsNetworkImage(url: avatar!) : Padding( padding: EdgeInsets.all(iconPadding), - child: SvgPicture.asset( + child: SuggestionsIcon( AssetStrings.profileIconImage, - package: AssetStrings.packageName, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), + color: context.theme.colorScheme.onSurface, ), ), ), diff --git a/lib/src/presentation/pages/widgets/bottom_sheets/confirmation_bottom_sheet.dart b/lib/src/presentation/pages/widgets/bottom_sheets/confirmation_bottom_sheet.dart index f806749..6d1bce6 100644 --- a/lib/src/presentation/pages/widgets/bottom_sheets/confirmation_bottom_sheet.dart +++ b/lib/src/presentation/pages/widgets/bottom_sheets/confirmation_bottom_sheet.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/bottom_sheets/base_bottom_sheet.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/clickable_list_item.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; import 'package:wtf_sliding_sheet/wtf_sliding_sheet.dart'; @@ -144,15 +144,10 @@ class _Confirm extends StatelessWidget { Widget build(BuildContext context) { return ClickableListItem( onClick: onConfirm, - leading: SvgPicture.asset( + leading: SuggestionsIcon( onConfirmAsset, - package: AssetStrings.packageName, - width: Dimensions.defaultSize, - height: Dimensions.defaultSize, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.error, - BlendMode.srcIn, - ), + size: Dimensions.defaultSize, + color: context.theme.colorScheme.error, ), title: Text( onConfirmText, @@ -178,15 +173,10 @@ class _Cancel extends StatelessWidget { Widget build(BuildContext context) { return ClickableListItem( onClick: onCancel, - leading: SvgPicture.asset( + leading: SuggestionsIcon( AssetStrings.closeIconImage, - package: AssetStrings.packageName, - width: Dimensions.defaultSize, - height: Dimensions.defaultSize, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), + size: Dimensions.defaultSize, + color: context.theme.colorScheme.onSurface, ), title: Text( onCancelText, diff --git a/lib/src/presentation/pages/widgets/bottom_sheets/edit_delete_bottom_sheet.dart b/lib/src/presentation/pages/widgets/bottom_sheets/edit_delete_bottom_sheet.dart index eb98787..6dccea2 100644 --- a/lib/src/presentation/pages/widgets/bottom_sheets/edit_delete_bottom_sheet.dart +++ b/lib/src/presentation/pages/widgets/bottom_sheets/edit_delete_bottom_sheet.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:suggest_a_feature/src/presentation/localization/localization_extensions.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/bottom_sheets/base_bottom_sheet.dart'; import 'package:suggest_a_feature/src/presentation/pages/widgets/clickable_list_item.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; import 'package:suggest_a_feature/src/presentation/utils/date_utils.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; @@ -99,15 +99,10 @@ class _EditItem extends StatelessWidget { localization.edit, style: context.theme.textTheme.titleMedium, ), - leading: SvgPicture.asset( + leading: SuggestionsIcon( AssetStrings.penIconImage, - package: AssetStrings.packageName, - height: Dimensions.defaultSize, - width: Dimensions.defaultSize, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), + size: Dimensions.defaultSize, + color: context.theme.colorScheme.onSurface, ), onClick: onEditClick, ); @@ -130,15 +125,10 @@ class _DeleteItem extends StatelessWidget { color: context.theme.colorScheme.error, ), ), - leading: SvgPicture.asset( + leading: SuggestionsIcon( AssetStrings.deleteIconImage, - package: AssetStrings.packageName, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.error, - BlendMode.srcIn, - ), - height: Dimensions.defaultSize, - width: Dimensions.defaultSize, + size: Dimensions.defaultSize, + color: context.theme.colorScheme.error, ), onClick: onDeleteClick, ); diff --git a/lib/src/presentation/pages/widgets/fab.dart b/lib/src/presentation/pages/widgets/fab.dart index cf452f3..fc75ea4 100644 --- a/lib/src/presentation/pages/widgets/fab.dart +++ b/lib/src/presentation/pages/widgets/fab.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; -import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; class SuggestionsFab extends StatefulWidget { @@ -90,15 +89,10 @@ class _SuggestionsFabState extends State ), ), Center( - child: SvgPicture.asset( + child: SuggestionsIcon( widget.imageIcon, - package: AssetStrings.packageName, - width: Dimensions.defaultSize, - height: Dimensions.defaultSize, - colorFilter: ColorFilter.mode( - widget.iconColor ?? context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), + size: Dimensions.defaultSize, + color: widget.iconColor ?? context.theme.colorScheme.onSurface, ), ), ], diff --git a/lib/src/presentation/pages/widgets/icon_button.dart b/lib/src/presentation/pages/widgets/icon_button.dart index c228c21..144b2f9 100644 --- a/lib/src/presentation/pages/widgets/icon_button.dart +++ b/lib/src/presentation/pages/widgets/icon_button.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; -import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; class SuggestionsIconButton extends StatefulWidget { @@ -39,17 +38,12 @@ class _SuggestionsIconButtonState extends State { onTapCancel: () => _onTap(false), child: Padding( padding: widget.padding, - child: SvgPicture.asset( + child: SuggestionsIcon( widget.imageIcon, - package: AssetStrings.packageName, - width: widget.size, - height: widget.size, - colorFilter: ColorFilter.mode( - _pressed - ? theme.actionPressedColor - : widget.color ?? context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), + size: widget.size, + color: _pressed + ? theme.actionPressedColor + : widget.color ?? context.theme.colorScheme.onSurface, ), ), ); diff --git a/lib/src/presentation/pages/widgets/suggestions_back_button.dart b/lib/src/presentation/pages/widgets/suggestions_back_button.dart index 0f246bd..bfd0fea 100644 --- a/lib/src/presentation/pages/widgets/suggestions_back_button.dart +++ b/lib/src/presentation/pages/widgets/suggestions_back_button.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; @@ -24,16 +24,11 @@ class SuggestionsBackButton extends StatelessWidget { left: Dimensions.marginDefault + Dimensions.marginMicro, right: Dimensions.marginMiddle, ), - child: SvgPicture.asset( + child: SuggestionsIcon( AssetStrings.backIconImage, - package: AssetStrings.packageName, - height: Dimensions.defaultSize, - width: Dimensions.defaultSize, - colorFilter: ColorFilter.mode( - context.theme.appBarTheme.iconTheme?.color ?? - context.theme.colorScheme.onSurface, - BlendMode.srcIn, - ), + size: Dimensions.defaultSize, + color: context.theme.appBarTheme.iconTheme?.color ?? + context.theme.colorScheme.onSurface, ), ), ); diff --git a/lib/src/presentation/pages/widgets/suggestions_icon.dart b/lib/src/presentation/pages/widgets/suggestions_icon.dart new file mode 100644 index 0000000..d00c8a6 --- /dev/null +++ b/lib/src/presentation/pages/widgets/suggestions_icon.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; +import 'package:vector_graphics/vector_graphics.dart'; + +class SuggestionsIcon extends StatelessWidget { + const SuggestionsIcon( + this.iconPath, { + this.size, + this.color, + this.fit, + super.key, + }); + + final String iconPath; + final double? size; + final Color? color; + final BoxFit? fit; + + @override + Widget build(BuildContext context) { + return VectorGraphic( + loader: AssetBytesLoader( + iconPath, + packageName: AssetStrings.packageName, + ), + width: size, + height: size, + colorFilter: + color != null ? ColorFilter.mode(color!, BlendMode.srcIn) : null, + fit: fit ?? BoxFit.contain, + ); + } +} diff --git a/lib/src/presentation/pages/widgets/votes_counter.dart b/lib/src/presentation/pages/widgets/votes_counter.dart index bc23fec..a5abd55 100644 --- a/lib/src/presentation/pages/widgets/votes_counter.dart +++ b/lib/src/presentation/pages/widgets/votes_counter.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart'; +import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_icon.dart'; import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart'; import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart'; @@ -23,15 +23,11 @@ class VotesCounter extends StatelessWidget { SizedBox( height: Dimensions.bigSize, width: Dimensions.bigSize, - child: SvgPicture.asset( + child: SuggestionsIcon( AssetStrings.suggestionsUpvoteArrow, - package: AssetStrings.packageName, - colorFilter: ColorFilter.mode( - isVoted - ? context.theme.colorScheme.primary - : theme.upvoteArrowColor, - BlendMode.srcIn, - ), + color: isVoted + ? context.theme.colorScheme.primary + : theme.upvoteArrowColor, fit: BoxFit.none, ), ), diff --git a/lib/src/presentation/utils/assets_strings.dart b/lib/src/presentation/utils/assets_strings.dart index bea6f50..4fdf599 100644 --- a/lib/src/presentation/utils/assets_strings.dart +++ b/lib/src/presentation/utils/assets_strings.dart @@ -1,25 +1,33 @@ class AssetStrings { static const String packageName = 'suggest_a_feature'; - static const String arrowDownIcon = 'assets/arrow_down_icon.svg'; - static const String addPhotoButton = 'assets/add_photo_icon.svg'; - static const String backIconImage = 'assets/arrow_left_icon.svg'; - static const String checkIconImage = 'assets/check_icon.svg'; - static const String closeIconImage = 'assets/close_icon.svg'; - static const String deleteIconImage = 'assets/delete_icon.svg'; - static const String downloadIconImage = 'assets/download_icon.svg'; - static const String notificationsIconImage = 'assets/notifications_icon.svg'; - static const String penIconImage = 'assets/pen_icon.svg'; - static const String profileIconImage = 'assets/profile_icon.svg'; - static const String plusIconThinImage = 'assets/plus_icon_thin.svg'; - static const String plusIconThickImage = 'assets/plus_icon_thick.svg'; + static const String arrowDownIcon = 'assets/compiled/arrow_down_icon.svg.vec'; + static const String addPhotoButton = 'assets/compiled/add_photo_icon.svg.vec'; + static const String backIconImage = 'assets/compiled/arrow_left_icon.svg.vec'; + static const String checkIconImage = 'assets/compiled/check_icon.svg.vec'; + static const String closeIconImage = 'assets/compiled/close_icon.svg.vec'; + static const String deleteIconImage = 'assets/compiled/delete_icon.svg.vec'; + static const String downloadIconImage = + 'assets/compiled/download_icon.svg.vec'; + static const String notificationsIconImage = + 'assets/compiled/notifications_icon.svg.vec'; + static const String penIconImage = 'assets/compiled/pen_icon.svg.vec'; + static const String profileIconImage = 'assets/compiled/profile_icon.svg.vec'; + static const String plusIconThinImage = + 'assets/compiled/plus_icon_thin.svg.vec'; + static const String plusIconThickImage = + 'assets/compiled/plus_icon_thick.svg.vec'; - static const String suggestionsRequests = 'assets/suggestions_requests.svg'; + static const String suggestionsRequests = + 'assets/compiled/suggestions_requests.svg.vec'; static const String suggestionsInProgress = - 'assets/suggestions_in_progress.svg'; - static const String suggestionsCompleted = 'assets/suggestions_completed.svg'; - static const String suggestionsDeclined = 'assets/suggestions_declined.svg'; + 'assets/compiled/suggestions_in_progress.svg.vec'; + static const String suggestionsCompleted = + 'assets/compiled/suggestions_completed.svg.vec'; + static const String suggestionsDeclined = + 'assets/compiled/suggestions_declined.svg.vec'; static const String suggestionsDuplicated = - 'assets/suggestions_duplicated.svg'; - static const String suggestionsUpvoteArrow = 'assets/arrow_up_suggestion.svg'; + 'assets/compiled/suggestions_duplicated.svg.vec'; + static const String suggestionsUpvoteArrow = + 'assets/compiled/arrow_up_suggestion.svg.vec'; } diff --git a/pubspec.yaml b/pubspec.yaml index e44ee87..73919d4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,16 +17,18 @@ dependencies: equatable: ^2.0.5 flutter: sdk: flutter - flutter_svg: ^2.0.9 intl: ^0.20.2 + vector_graphics: ^1.1.19 wtf_sliding_sheet: ^1.1.3 dev_dependencies: build_runner: ^2.4.7 flutter_test: sdk: flutter + vector_graphics_compiler: ^1.1.19 very_good_analysis: ^5.1.0 flutter: assets: - assets/ + - assets/compiled/ diff --git a/scripts/compile_svgs.dart b/scripts/compile_svgs.dart new file mode 100644 index 0000000..321ad26 --- /dev/null +++ b/scripts/compile_svgs.dart @@ -0,0 +1,105 @@ +// Script needs print for CLI progress/output +// ignore_for_file: avoid_print + +/// Compiles all SVG assets to .vec format for vector_graphics package. +/// +/// This script processes all SVG files in the assets/ directory and generates +/// corresponding .vec files in assets/compiled/. +/// +/// Run this script whenever SVG files are added or modified: +/// dart run scripts/compile_svgs.dart +/// +/// Why this is needed: +/// The vector_graphics package requires pre-compiled .vec files when used in +/// a library package. The asset transformer approach only works in +/// applications, not across package boundaries. + +library; + +import 'dart:io'; + +const String _assetsPath = 'assets'; +const String _compiledRelativePath = 'compiled'; +const String _compiledPath = '$_assetsPath/$_compiledRelativePath'; + +void main() async { + final assetsDir = Directory(_assetsPath); + final compiledDir = Directory(_compiledPath); + + // Ensure compiled directory exists + if (!compiledDir.existsSync()) { + await compiledDir.create(recursive: true); + print('Created $_compiledPath/ directory'); + } + + // Find all SVG files + final svgFiles = []; + await for (final entity in assetsDir.list()) { + if (entity is File && entity.path.endsWith('.svg')) { + svgFiles.add(entity); + } + } + + if (svgFiles.isEmpty) { + print('No SVG files found in $_assetsPath/'); + return; + } + + print('Found ${svgFiles.length} SVG file(s) to compile...\n'); + + // Compile all SVG files in parallel + final compilationTasks = >[]; + + for (final svgFile in svgFiles) { + final fileName = svgFile.uri.pathSegments.last; + final inputPath = svgFile.path; + final outputPath = + '${compiledDir.path}${Platform.pathSeparator}$fileName.vec'; + + compilationTasks.add(_compileSvg(fileName, inputPath, outputPath)); + } + + // Wait for all compilations to complete and count results + final results = await Future.wait(compilationTasks); + final successCount = results.where((success) => success).length; + final errorCount = results.where((success) => !success).length; + + print('\n─────────────────────────────────────'); + print('Compilation complete!'); + print('Success: $successCount | Errors: $errorCount'); + print('─────────────────────────────────────'); +} + +/// Compiles a single SVG file to .vec format. +/// Prints the result immediately and returns true on success, false on error. +Future _compileSvg( + String fileName, + String inputPath, + String outputPath, +) async { + try { + final result = await Process.run( + 'dart', + [ + 'run', + 'vector_graphics_compiler', + '-i', + inputPath, + '-o', + outputPath, + ], + ); + + if (result.exitCode == 0) { + print('✓ $fileName -> $_compiledRelativePath/$fileName.vec'); + return true; + } else { + final error = result.stderr.toString().trim(); + print('✗ $fileName - Error: $error'); + return false; + } + } on Exception catch (e) { + print('✗ $fileName - Error: $e'); + return false; + } +}