diff --git a/client/flutter/divkit/CHANGELOG.md b/client/flutter/divkit/CHANGELOG.md index d27e93328..cca802b83 100644 --- a/client/flutter/divkit/CHANGELOG.md +++ b/client/flutter/divkit/CHANGELOG.md @@ -2,6 +2,7 @@ * Fix sticky switching of states * Fix inner objects in templates breaks rendering +* Add support div-text features: font_family, letter_spacing font_weight_value, text_shadow ## 0.3.0 diff --git a/client/flutter/divkit/lib/src/core/widgets/input/div_input_model.dart b/client/flutter/divkit/lib/src/core/widgets/input/div_input_model.dart index ffd311752..dffad3bc7 100644 --- a/client/flutter/divkit/lib/src/core/widgets/input/div_input_model.dart +++ b/client/flutter/divkit/lib/src/core/widgets/input/div_input_model.dart @@ -50,11 +50,13 @@ class DivInputModel with EquatableMixin { } }); - final styleUnit = data.fontSizeUnit.value!.asPx; - final lineHeight = data.lineHeight?.value!; + final styleUnit = data.fontSizeUnit.requireValue.asPx; + final lineHeight = data.lineHeight?.requireValue; + final fontFamily = data.fontFamily?.requireValue; final fontSize = data.fontSize.value!.toDouble() * textScale; final style = TextStyle( + fontFamily: fontFamily, fontSize: fontSize * styleUnit, color: data.textColor.value!, height: lineHeight != null ? lineHeight * viewScale / fontSize : null, @@ -62,15 +64,15 @@ class DivInputModel with EquatableMixin { ); final hintStyle = style.copyWith( - color: data.hintColor.value!, + color: data.hintColor.requireValue, ); - final keyboardType = data.keyboardType.value!; + final keyboardType = data.keyboardType.requireValue; if (variables.context.current[data.textVariable] != controller.text) { controller.text = variables.context.current[data.textVariable] ?? ''; } - final newFocusNodeId = data.focus?.nextFocusIds?.forward?.value!; + final newFocusNodeId = data.focus?.nextFocusIds?.forward?.requireValue; final alignment = PassDivTextAlignment( data.textAlignmentVertical, @@ -82,8 +84,8 @@ class DivInputModel with EquatableMixin { return DivInputModel( textStyle: style, hintStyle: hintStyle, - hintText: data.hintText?.value!, - maxLines: obscureText ? 1 : data.maxVisibleLines?.value!, + hintText: data.hintText?.requireValue, + maxLines: obscureText ? 1 : data.maxVisibleLines?.requireValue, obscureText: obscureText, keyboardType: keyboardType.map( singleLineText: () => TextInputType.text, @@ -124,6 +126,7 @@ class DivInputModel with EquatableMixin { final textScale = divScalingModel?.textScale ?? 1; return variables.watch((context) async { + final fontFamily = await data.fontFamily?.resolveValue(context: context); final styleUnit = (await data.fontSizeUnit.resolveValue( context: context, )) @@ -138,6 +141,7 @@ class DivInputModel with EquatableMixin { textScale; final style = TextStyle( + fontFamily: fontFamily, fontSize: fontSize * styleUnit, color: await data.textColor.resolveValue( context: context, @@ -236,5 +240,6 @@ class DivInputModel with EquatableMixin { onFocusActions, textAlign, textAlignVertical, + obscureText, ]; } diff --git a/client/flutter/divkit/lib/src/core/widgets/text/div_text_model.dart b/client/flutter/divkit/lib/src/core/widgets/text/div_text_model.dart index 403b62c13..a80820864 100644 --- a/client/flutter/divkit/lib/src/core/widgets/text/div_text_model.dart +++ b/client/flutter/divkit/lib/src/core/widgets/text/div_text_model.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:divkit/divkit.dart'; import 'package:divkit/src/core/widgets/text/utils/div_range_helper.dart'; import 'package:divkit/src/core/widgets/text/utils/div_text_range_model.dart'; @@ -38,16 +39,25 @@ class DivTextModel with EquatableMixin { ); final autoEllipsize = data.autoEllipsize?.value ?? false; + final fontFamily = data.fontFamily?.requireValue; - final fontSize = data.fontSize.value!.toDouble() * - data.fontSizeUnit.value!.asPx * + final fontSize = data.fontSize.requireValue.toDouble() * + data.fontSizeUnit.requireValue.asPx * textScale; - final lineHeight = data.lineHeight?.value!.toDouble(); + final lineHeight = data.lineHeight?.requireValue.toDouble(); - final underline = data.underline.value!; + final letterSpacing = data.letterSpacing.requireValue; + final underline = data.underline.requireValue; - final strike = data.strike.value!; + final strike = data.strike.requireValue; + final shadow = data.textShadow?.valueShadow(viewScale: viewScale); + + final fontWeightValue = data.fontWeightValue?.requireValue; + FontWeight? fontWeight = FontWeight.values.firstWhereOrNull( + (element) => element.value == fontWeightValue, + ); + fontWeight ??= data.fontWeight.passValue(); final linesStyleList = [ underline, @@ -56,30 +66,34 @@ class DivTextModel with EquatableMixin { final style = TextStyle( fontSize: fontSize, + fontFamily: fontFamily, + shadows: shadow != null ? [shadow] : null, height: lineHeight != null - ? (lineHeight * data.fontSizeUnit.value!.asPx) * + ? (lineHeight * data.fontSizeUnit.requireValue.asPx) * viewScale / fontSize : null, color: data.textColor.value!, - fontWeight: data.fontWeight.passValue(), + fontWeight: fontWeight, + letterSpacing: letterSpacing, decoration: TextDecoration.combine( [ underline.asUnderline, strike.asLineThrough, ], ), - decorationColor: data.textColor.value!, + decorationColor: data.textColor.requireValue, overflow: autoEllipsize ? TextOverflow.ellipsis : null, ); - final text = data.text.value!; + final text = data.text.requireValue; final rangesList = DivRangeHelper.getRangeItemsSync( text, data.ranges ?? [], style, linesStyleList, + viewScale, ); return DivTextModel( @@ -88,7 +102,7 @@ class DivTextModel with EquatableMixin { style: style, textBoxAlignment: alignment.valueAlignmentGeometry(), textAlign: alignment.valueTextAlign(), - maxLines: data.maxLines?.value!, + maxLines: data.maxLines?.requireValue, ); } catch (e, st) { logger.warning( @@ -122,6 +136,10 @@ class DivTextModel with EquatableMixin { ) ?? false; + final fontFamily = (await data.fontFamily?.resolveValue( + context: context, + )); + final fontSize = (await data.fontSize.resolveValue( context: context, )) @@ -145,13 +163,33 @@ class DivTextModel with EquatableMixin { context: context, ); + final letterSpacing = await data.letterSpacing.resolveValue( + context: context, + ); + final linesStyleList = [ underline, strike, ]; + final fontWeightValue = await data.fontWeightValue?.resolveValue( + context: context, + ); + FontWeight? fontWeight = FontWeight.values.firstWhereOrNull( + (element) => element.value == fontWeightValue, + ); + fontWeight ??= await data.fontWeight.resolve(context: context); + + final shadow = await data.textShadow?.resolveShadow( + context: context, + viewScale: viewScale, + ); + final style = TextStyle( + fontFamily: fontFamily, fontSize: fontSize, + letterSpacing: letterSpacing, + shadows: shadow != null ? [shadow] : null, height: lineHeight != null ? (lineHeight * (await data.fontSizeUnit.resolveValue( @@ -164,9 +202,7 @@ class DivTextModel with EquatableMixin { color: await data.textColor.resolveValue( context: context, ), - fontWeight: await data.fontWeight.resolve( - context: context, - ), + fontWeight: fontWeight, decoration: TextDecoration.combine( [ underline.asUnderline, @@ -189,6 +225,7 @@ class DivTextModel with EquatableMixin { context, style, linesStyleList, + viewScale, ); return DivTextModel( diff --git a/client/flutter/divkit/lib/src/core/widgets/text/utils/div_range_helper.dart b/client/flutter/divkit/lib/src/core/widgets/text/utils/div_range_helper.dart index 6bc9fded6..d0843b081 100644 --- a/client/flutter/divkit/lib/src/core/widgets/text/utils/div_range_helper.dart +++ b/client/flutter/divkit/lib/src/core/widgets/text/utils/div_range_helper.dart @@ -10,6 +10,7 @@ class DivRangeHelper { DivVariableContext context, TextStyle style, List linesStyleList, + double viewScale, ) async { final inputMap = {}; for (var range in divTextRange) { @@ -18,6 +19,7 @@ class DivRangeHelper { style, context, linesStyleList, + viewScale, ); inputMap.addEntries([mapEntry]); } @@ -44,6 +46,7 @@ class DivRangeHelper { List divTextRange, TextStyle style, List linesStyleList, + double viewScale, ) { final inputMap = {}; for (var range in divTextRange) { @@ -51,6 +54,7 @@ class DivRangeHelper { range, style, linesStyleList, + viewScale, ); inputMap.addEntries([mapEntry]); } @@ -78,6 +82,7 @@ class DivRangeHelper { TextStyle style, DivVariableContext context, List linesStyleList, + double viewScale, ) async { final start = await divTextRange.start.resolveValue( context: context, @@ -113,6 +118,10 @@ class DivRangeHelper { }, ); + final fontFamily = await divTextRange.fontFamily?.resolveValue( + context: context, + ); + final fontSize = await divTextRange.fontSize?.resolveValue( context: context, ); @@ -132,6 +141,11 @@ class DivRangeHelper { context: context, ); + final shadow = await divTextRange.textShadow?.resolveShadow( + context: context, + viewScale: viewScale, + ); + List actions = []; List? actionsDto = [...?divTextRange.actions]; for (final action in actionsDto) { @@ -144,6 +158,8 @@ class DivRangeHelper { } style = TextStyle( color: textColor, + shadows: shadow != null ? [shadow] : null, + fontFamily: fontFamily, fontSize: fontSize?.toDouble(), fontWeight: fontWeight, backgroundColor: background, @@ -174,6 +190,7 @@ class DivRangeHelper { DivTextRange divTextRange, TextStyle style, List linesStyleList, + double viewScale, ) { final start = divTextRange.start.value!; final end = divTextRange.end.value!; @@ -193,6 +210,8 @@ class DivRangeHelper { }, ); + final fontFamily = divTextRange.fontFamily?.value!; + final fontSize = divTextRange.fontSize?.value!; final fontWeightValue = divTextRange.fontWeightValue?.value!; @@ -204,6 +223,8 @@ class DivRangeHelper { final letterSpacing = divTextRange.letterSpacing?.value!; + final shadow = divTextRange.textShadow?.valueShadow(viewScale: viewScale); + List actions = []; List? actionsDto = [...?divTextRange.actions]; for (final action in actionsDto) { @@ -214,6 +235,8 @@ class DivRangeHelper { } style = TextStyle( color: textColor, + shadows: shadow != null ? [shadow] : null, + fontFamily: fontFamily, fontSize: fontSize?.toDouble(), fontWeight: fontWeight, backgroundColor: background, diff --git a/client/flutter/divkit/lib/src/utils/converters.dart b/client/flutter/divkit/lib/src/utils/converters.dart index 7f30c44bc..cdd28de81 100644 --- a/client/flutter/divkit/lib/src/utils/converters.dart +++ b/client/flutter/divkit/lib/src/utils/converters.dart @@ -1171,6 +1171,58 @@ extension PassDivBorder on DivBorder { } } +extension PassDivShadow on DivShadow { + Future resolveBoxShadow({ + required DivVariableContext context, + required double viewScale, + }) async => + BoxShadow( + color: (await color.resolveValue(context: context)).withOpacity( + await alpha.resolveValue(context: context), + ), + blurRadius: + (await blur.resolveValue(context: context)).toDouble() * viewScale, + offset: + await offset.resolveOffset(context: context, viewScale: viewScale), + ); + + BoxShadow? valueBoxShadow({ + required double viewScale, + }) => + BoxShadow( + color: color.requireValue.withOpacity(alpha.requireValue), + blurRadius: blur.requireValue.toDouble() * viewScale, + offset: offset.valueOffset( + viewScale: viewScale, + ), + ); + + Future resolveShadow({ + required DivVariableContext context, + required double viewScale, + }) async => + Shadow( + color: (await color.resolveValue(context: context)).withOpacity( + await alpha.resolveValue(context: context), + ), + blurRadius: + (await blur.resolveValue(context: context)).toDouble() * viewScale, + offset: + await offset.resolveOffset(context: context, viewScale: viewScale), + ); + + Shadow? valueShadow({ + required double viewScale, + }) => + Shadow( + color: color.requireValue.withOpacity(alpha.requireValue), + blurRadius: blur.requireValue.toDouble() * viewScale, + offset: offset.valueOffset( + viewScale: viewScale, + ), + ); +} + extension PassDivFontWeight on Expression { Future resolve({ required DivVariableContext context,