From e2ee6b802a8176e28b6056cfc575fb85bdc8bf0f Mon Sep 17 00:00:00 2001 From: Gerhard Date: Mon, 31 Jul 2023 16:25:51 +0200 Subject: [PATCH] use fractions FontFeature Signed-off-by: Gerhard --- .../widgets/recipe_detail_tabbar_widget.dart | 26 +------- .../recipe_shopping_list_stateful_widget.dart | 27 +------- .../recipe_upsert_steps_stateful_widget.dart | 10 ++- lib/pages/recipe_upsert_page.dart | 9 ++- lib/pages/shopping_list_page.dart | 22 ++++++- lib/utils.dart | 66 +++++++++++++++++++ 6 files changed, 105 insertions(+), 55 deletions(-) create mode 100644 lib/utils.dart diff --git a/lib/components/widgets/recipe_detail_tabbar_widget.dart b/lib/components/widgets/recipe_detail_tabbar_widget.dart index 27e3b96..9277fbc 100644 --- a/lib/components/widgets/recipe_detail_tabbar_widget.dart +++ b/lib/components/widgets/recipe_detail_tabbar_widget.dart @@ -3,11 +3,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:untare/cubits/settings_cubit.dart'; import 'package:untare/models/ingredient.dart'; import 'package:untare/models/recipe.dart'; -import 'package:untare/extensions/double_extension.dart'; import 'package:flutter_gen/gen_l10n/app_locales.dart'; import 'package:collapsible/collapsible.dart'; -import 'package:fraction/fraction.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:untare/utils.dart'; class RecipeDetailTabBarWidget extends StatefulWidget { final Recipe recipe; @@ -274,27 +273,6 @@ class RecipeDetailTabBarWidgetState extends State { bool? useFractions = (settingsCubit.state.userServerSetting!.useFractions == true); double rawAmount = ingredient.amount * newServing / initServing; - String amount = (ingredient.amount > 0) ? ('${rawAmount.toFormattedString()} ') : ''; - if (amount != '' && useFractions == true && (rawAmount % 1) != 0) { - // If we have a complex decimal we build a "simple" fraction. Otherwise we do the normal one - if ((((rawAmount - rawAmount.toInt()) * 100) % 5) != 0) { - // Use this crap because we can't change precision programmatically - if (rawAmount.toInt() < 1) { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-1).reduce()} '; - } else if (rawAmount.toInt() < 10) { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-2).reduce()} '; - } else if (rawAmount.toInt() < 100) { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-3).reduce()} '; - } else if(rawAmount.toInt() < 1000) { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-4).reduce()} '; - } else { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-5).reduce()} '; - } - } else { - amount = '${MixedFraction.fromDouble(rawAmount)} '; - } - } - String unit = (ingredient.amount > 0 && ingredient.unit != null) ? ('${ingredient.unit!.getUnitName(rawAmount)} ') : ''; String food = (ingredient.food != null) ? ('${ingredient.food!.getFoodName(rawAmount)} ') : ''; String note = (ingredient.note != null && ingredient.note != '') ? ('(${ingredient.note!})') : ''; @@ -315,7 +293,7 @@ class RecipeDetailTabBarWidgetState extends State { contentPadding: const EdgeInsets.fromLTRB(5, 0, 5, 0), title: Wrap( children: [ - Text(amount, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)), + amountWrap(rawAmount, useFractions), Text(unit, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)), Text(food, style: const TextStyle(fontSize: 15)), Text( diff --git a/lib/components/widgets/recipe_shopping_list_stateful_widget.dart b/lib/components/widgets/recipe_shopping_list_stateful_widget.dart index 80809cd..312fc12 100644 --- a/lib/components/widgets/recipe_shopping_list_stateful_widget.dart +++ b/lib/components/widgets/recipe_shopping_list_stateful_widget.dart @@ -1,14 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_locales.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:fraction/fraction.dart'; import 'package:untare/blocs/recipe/recipe_bloc.dart'; import 'package:untare/blocs/recipe/recipe_event.dart'; import 'package:untare/blocs/recipe/recipe_state.dart'; import 'package:untare/blocs/shopping_list/shopping_list_bloc.dart'; import 'package:untare/components/loading_component.dart'; import 'package:untare/cubits/settings_cubit.dart'; -import 'package:untare/extensions/double_extension.dart'; import 'package:untare/models/food.dart'; import 'package:untare/models/ingredient.dart'; import 'package:untare/models/recipe.dart'; @@ -17,6 +15,8 @@ import 'package:untare/models/step.dart'; import 'package:untare/services/api/api_food.dart'; import 'package:untare/services/api/api_shopping_list.dart'; +import 'package:untare/utils.dart'; + class RecipeShoppingListWidget extends StatefulWidget { final Recipe recipe; final BuildContext btsContext; @@ -224,27 +224,6 @@ class RecipeShoppingListWidgetState extends State { bool? useFractions = (settingsCubit.state.userServerSetting!.useFractions == true); double rawAmount = ingredient.amount * newServing / initServing; - String amount = (ingredient.amount > 0) ? ('${rawAmount.toFormattedString()} ') : ''; - if (amount != '' && useFractions == true && (rawAmount % 1) != 0) { - // If we have a complex decimal we build a "simple" fraction. Otherwise we do the normal one - if ((((rawAmount - rawAmount.toInt()) * 100) % 5) != 0) { - // Use this crap because we can't change precision programmatically - if (rawAmount.toInt() < 1) { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-1).reduce()} '; - } else if (rawAmount.toInt() < 10) { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-2).reduce()} '; - } else if (rawAmount.toInt() < 100) { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-3).reduce()} '; - } else if(rawAmount.toInt() < 1000) { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-4).reduce()} '; - } else { - amount = '${MixedFraction.fromDouble(rawAmount, precision: 1.0e-5).reduce()} '; - } - } else { - amount = '${MixedFraction.fromDouble(rawAmount)} '; - } - } - String unit = (ingredient.unit != null && ingredient.amount > 0) ? ('${ingredient.unit!.getUnitName(rawAmount)} ') : ''; String food = (ingredient.food != null) ? ('${ingredient.food!.getFoodName(rawAmount)} ') : ''; bool? checkBoxValue = !(ingredient.food != null && ingredient.food!.onHand!); @@ -292,7 +271,7 @@ class RecipeShoppingListWidgetState extends State { ), title: Wrap( children: [ - Text(amount, style: const TextStyle(fontWeight: FontWeight.bold)), + amountWrap(rawAmount, useFractions), Text(unit, style: const TextStyle(fontWeight: FontWeight.bold)), Text(food), ], diff --git a/lib/components/widgets/recipe_upsert_steps_stateful_widget.dart b/lib/components/widgets/recipe_upsert_steps_stateful_widget.dart index ff90528..7b818fd 100644 --- a/lib/components/widgets/recipe_upsert_steps_stateful_widget.dart +++ b/lib/components/widgets/recipe_upsert_steps_stateful_widget.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:untare/components/dialogs/upsert_recipe_ingredient_dialog.dart'; -import 'package:untare/extensions/double_extension.dart'; +import 'package:untare/cubits/settings_cubit.dart'; import 'package:untare/models/ingredient.dart'; import 'package:untare/models/recipe.dart'; import 'package:untare/models/step.dart'; +import 'package:untare/utils.dart'; import 'package:drag_and_drop_lists/drag_and_drop_lists.dart'; import 'package:flutter_gen/gen_l10n/app_locales.dart'; @@ -254,7 +256,9 @@ class RecipeUpsertStepsWidgetState extends State { Widget buildIngredient(Ingredient ingredient, int stepIndex, int ingredientIndex) { // Build ingredient text layout - String amount = (ingredient.amount > 0) ? ('${ingredient.amount.toFormattedString()} ') : ''; + SettingsCubit settingsCubit = context.read(); + bool? useFractions = (settingsCubit.state.userServerSetting!.useFractions == true); + String unit = (ingredient.unit != null) ? ('${ingredient.unit!.name} ') : ''; String food = (ingredient.food != null) ? ('${ingredient.food!.name} ') : ''; String note = (ingredient.note != null && ingredient.note != '') ? ('(${ingredient.note !})') : ''; @@ -304,7 +308,7 @@ class RecipeUpsertStepsWidgetState extends State { contentPadding: const EdgeInsets.fromLTRB(5, 0, 5, 0), title: Wrap( children: [ - Text(amount, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)), + amountWrap(ingredient.amount, useFractions), Text(unit, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)), Text(food, style: const TextStyle(fontSize: 15)), Text( diff --git a/lib/pages/recipe_upsert_page.dart b/lib/pages/recipe_upsert_page.dart index 2237fa9..477c4ca 100644 --- a/lib/pages/recipe_upsert_page.dart +++ b/lib/pages/recipe_upsert_page.dart @@ -17,11 +17,12 @@ import 'package:untare/blocs/recipe/recipe_state.dart'; import 'package:untare/components/dialogs/upsert_recipe_ingredient_dialog.dart'; import 'package:untare/components/loading_component.dart'; import 'package:untare/components/recipes/recipe_image_component.dart'; -import 'package:untare/extensions/double_extension.dart'; +import 'package:untare/cubits/settings_cubit.dart'; import 'package:untare/futures/future_api_cache_keywords.dart'; import 'package:untare/models/ingredient.dart'; import 'package:untare/models/keyword.dart'; import 'package:untare/models/recipe.dart'; +import 'package:untare/utils.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:untare/models/step.dart'; import 'package:untare/pages/recipe_detail_page.dart'; @@ -777,7 +778,9 @@ class RecipeUpsertPageState extends State { Widget buildIngredient(Ingredient ingredient, int stepIndex, int ingredientIndex) { // Build ingredient text layout - String amount = (ingredient.amount > 0) ? ('${ingredient.amount.toFormattedString()} ') : ''; + SettingsCubit settingsCubit = context.read(); + bool? useFractions = (settingsCubit.state.userServerSetting!.useFractions == true); + String unit = (ingredient.amount > 0 && ingredient.unit != null) ? ('${ingredient.unit!.getUnitName(ingredient.amount)} ') : ''; String food = (ingredient.food != null) ? ('${ingredient.food!.getFoodName(ingredient.amount)} ') : ''; String note = (ingredient.note != null && ingredient.note != '') ? ('(${ingredient.note !})') : ''; @@ -828,7 +831,7 @@ class RecipeUpsertPageState extends State { contentPadding: const EdgeInsets.fromLTRB(5, 0, 5, 0), title: Wrap( children: [ - Text(amount, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)), + amountWrap(ingredient.amount, useFractions), Text(unit, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15)), Text(food, style: const TextStyle(fontSize: 15)), Text( diff --git a/lib/pages/shopping_list_page.dart b/lib/pages/shopping_list_page.dart index 88e2559..a4b54ff 100644 --- a/lib/pages/shopping_list_page.dart +++ b/lib/pages/shopping_list_page.dart @@ -1,12 +1,14 @@ // ignore_for_file: avoid_function_literals_in_foreach_calls import 'dart:async'; +import 'dart:ui'; import 'package:configurable_expansion_tile_null_safety/configurable_expansion_tile_null_safety.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_locales.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:fraction/fraction.dart'; import 'package:untare/blocs/recipe/recipe_bloc.dart'; import 'package:untare/blocs/recipe/recipe_state.dart'; import 'package:untare/blocs/shopping_list/shopping_list_bloc.dart'; @@ -414,6 +416,9 @@ class ShoppingListPageState extends State with TickerProviderS } Widget buildShoppingListEntryWidget(ShoppingListEntry shoppingListEntry, {bool? grouped}) { + SettingsCubit settingsCubit = context.read(); + bool? useFractions = (settingsCubit.state.userServerSetting!.useFractions == true); + String amount = (shoppingListEntry.amount > 0) ? ('${shoppingListEntry.amount.toFormattedString()} ') : ''; String unit = (shoppingListEntry.amount > 0 && shoppingListEntry.unit != null) ? ('${shoppingListEntry.unit!.getUnitName(shoppingListEntry.amount)} ') : ''; String food = (shoppingListEntry.food != null) ? (shoppingListEntry.food!.getFoodName(shoppingListEntry.amount)) : ''; @@ -473,7 +478,22 @@ class ShoppingListPageState extends State with TickerProviderS RichText( text: TextSpan( children: [ - TextSpan(text: amount, style: TextStyle(color: Theme.of(context).primaryTextTheme.bodyText1!.color, fontWeight: FontWeight.bold)), + TextSpan( + children: (useFractions == false || shoppingListEntry.amount % 1 == 0) + ? [TextSpan(text: amount)] + : [ + TextSpan( + text: '${shoppingListEntry.amount.toInt()} ', + ), + TextSpan( + text: + '${MixedFraction.fromDouble(shoppingListEntry.amount % 1).reduce()} ', + style: const TextStyle( + fontFeatures: [FontFeature.fractions()])) + ], + style: TextStyle( + color: Theme.of(context).primaryTextTheme.bodyText1!.color, + fontWeight: FontWeight.bold)), TextSpan(text: unit, style: TextStyle(color: Theme.of(context).primaryTextTheme.bodyText1!.color, fontWeight: FontWeight.bold)), TextSpan(text: food, style: TextStyle(color: Theme.of(context).primaryTextTheme.bodyText1!.color)), ], diff --git a/lib/utils.dart b/lib/utils.dart new file mode 100644 index 0000000..5cd1d69 --- /dev/null +++ b/lib/utils.dart @@ -0,0 +1,66 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:fraction/fraction.dart'; +import 'package:untare/extensions/double_extension.dart'; + +String doubleToFractionString(double rawAmount) { + // If we have a complex decimal we build a "simple" fraction. Otherwise we do the normal one + if ((((rawAmount % 1) * 100) % 5) != 0) { + // Use this crap because we can't change precision programmatically + if (rawAmount.toInt() < 1) { + return '${MixedFraction.fromDouble(rawAmount % 1, precision: 1.0e-1).reduce()} '; + } else if (rawAmount.toInt() < 10) { + return '${MixedFraction.fromDouble(rawAmount % 1, precision: 1.0e-2).reduce()} '; + } else if (rawAmount.toInt() < 100) { + return '${MixedFraction.fromDouble(rawAmount % 1, precision: 1.0e-3).reduce()} '; + } else if (rawAmount.toInt() < 1000) { + return '${MixedFraction.fromDouble(rawAmount % 1, precision: 1.0e-4).reduce()} '; + } else { + return '${MixedFraction.fromDouble(rawAmount % 1, precision: 1.0e-5).reduce()} '; + } + } else { + return '${MixedFraction.fromDouble(rawAmount % 1)} '; + } +} + +Wrap amountWrap(double rawAmount, bool useFractions) { + List child = []; + + if (rawAmount == 0) { + // nothing to do + return Wrap(); + } + + if (useFractions == true && (rawAmount % 1) != 0) { + if (rawAmount >= 1.0) { + child.add(Text( + '${rawAmount.toInt().toString()} ', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + ), + )); + } + child.add(Text( + '${doubleToFractionString(rawAmount % 1)} ', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + fontFeatures: [FontFeature.fractions()], + ), + )); + } else { + child.add(Text( + '${rawAmount.toFormattedString()} ', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + ), + )); + } + + return Wrap( + children: child, + ); +}