fixed text / strut styles
This commit is contained in:
parent
2d5de662ff
commit
81977ea4d8
18 changed files with 59 additions and 59 deletions
|
@ -3,10 +3,6 @@ import 'dart:ui';
|
|||
import 'package:flutter/painting.dart';
|
||||
|
||||
class AStyles {
|
||||
// as of Flutter v2.8.0, overflowing `Text` miscalculates height and some text (e.g. 'Å') is clipped
|
||||
// so we give it a `strutStyle` with a slightly larger height
|
||||
static const overflowStrut = StrutStyle(height: 1.3);
|
||||
|
||||
static const knownTitleText = TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w300,
|
||||
|
|
|
@ -112,7 +112,6 @@ class _RandomTextSpanHighlighterState extends State<_RandomTextSpanHighlighter>
|
|||
])
|
||||
],
|
||||
),
|
||||
strutStyle: const StrutStyle(height: 1.5, forceStrutHeight: true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'package:aves/model/settings/enums/coordinate_format.dart';
|
|||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/format.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/utils/collection_utils.dart';
|
||||
import 'package:aves/utils/file_utils.dart';
|
||||
|
@ -60,7 +59,6 @@ class EntryListDetails extends StatelessWidget {
|
|||
children: spans,
|
||||
),
|
||||
style: style,
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:aves/theme/format.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
@ -29,11 +28,16 @@ class EntryListDetailsTheme extends StatelessWidget {
|
|||
final textScaler = mq.textScaler;
|
||||
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
final titleStyle = textTheme.bodyMedium!;
|
||||
final captionStyle = textTheme.bodySmall!;
|
||||
// specify `height` for accurate paragraph height measurement
|
||||
final defaultTextHeight = DefaultTextStyle.of(context).style.height;
|
||||
final titleStyle = textTheme.bodyMedium!.copyWith(height: defaultTextHeight);
|
||||
final captionStyle = textTheme.bodySmall!.copyWith(height: defaultTextHeight);
|
||||
|
||||
final titleLineHeightParagraph = RenderParagraph(
|
||||
TextSpan(text: 'Fake Title', style: titleStyle),
|
||||
TextSpan(
|
||||
text: 'Fake Title',
|
||||
style: titleStyle,
|
||||
),
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaler: textScaler,
|
||||
)..layout(const BoxConstraints(), parentUsesSize: true);
|
||||
|
@ -41,10 +45,12 @@ class EntryListDetailsTheme extends StatelessWidget {
|
|||
titleLineHeightParagraph.dispose();
|
||||
|
||||
final captionLineHeightParagraph = RenderParagraph(
|
||||
TextSpan(text: formatDateTime(DateTime.now(), locale, use24hour), style: captionStyle),
|
||||
TextSpan(
|
||||
text: formatDateTime(DateTime.now(), locale, use24hour),
|
||||
style: captionStyle,
|
||||
),
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaler: textScaler,
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
)..layout(const BoxConstraints(), parentUsesSize: true);
|
||||
final captionLineHeight = captionLineHeightParagraph.getMaxIntrinsicHeight(double.infinity);
|
||||
|
||||
|
|
|
@ -29,6 +29,14 @@ class _AnimatedDiffTextState extends State<AnimatedDiffText> with SingleTickerPr
|
|||
late final Animation<double> _animation;
|
||||
final List<_TextDiff> _diffs = [];
|
||||
|
||||
TextStyle get _textStyle {
|
||||
final style = widget.textStyle ?? const TextStyle();
|
||||
// specify `height` for accurate paragraph height measurement
|
||||
return style.copyWith(height: style.height ?? DefaultTextStyle.of(context).style.height);
|
||||
}
|
||||
|
||||
StrutStyle? get _strutStyle => widget.strutStyle;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -101,24 +109,25 @@ class _AnimatedDiffTextState extends State<AnimatedDiffText> with SingleTickerPr
|
|||
child: Text(
|
||||
text,
|
||||
key: Key(text),
|
||||
style: _textStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
strutStyle: widget.strutStyle,
|
||||
strutStyle: _strutStyle,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Size textSize(String text) {
|
||||
Size _textSize(String text) {
|
||||
final paragraph = RenderParagraph(
|
||||
TextSpan(text: text, style: widget.textStyle),
|
||||
TextSpan(text: text, style: _textStyle),
|
||||
textDirection: Directionality.of(context),
|
||||
textScaler: MediaQuery.textScalerOf(context),
|
||||
strutStyle: widget.strutStyle,
|
||||
strutStyle: _strutStyle,
|
||||
)..layout(const BoxConstraints(), parentUsesSize: true);
|
||||
final width = paragraph.getMaxIntrinsicWidth(double.infinity);
|
||||
final height = paragraph.getMaxIntrinsicHeight(double.infinity);
|
||||
|
@ -140,7 +149,7 @@ class _AnimatedDiffTextState extends State<AnimatedDiffText> with SingleTickerPr
|
|||
..clear()
|
||||
..addAll(d.map((diff) {
|
||||
final text = diff.text;
|
||||
final size = textSize(text);
|
||||
final size = _textSize(text);
|
||||
return switch (diff.operation) {
|
||||
Operation.delete => (text, null, size, Size.zero),
|
||||
Operation.insert => (null, text, Size.zero, size),
|
||||
|
|
|
@ -68,7 +68,7 @@ class SectionHeader<T> extends StatelessWidget {
|
|||
sectionKey: sectionKey,
|
||||
browsingBuilder: leading != null
|
||||
? (context) => Container(
|
||||
padding: const EdgeInsetsDirectional.only(end: 8, bottom: 4),
|
||||
padding: const EdgeInsetsDirectional.only(end: 8),
|
||||
width: leadingSize.width,
|
||||
height: leadingSize.height,
|
||||
child: leading,
|
||||
|
@ -80,7 +80,7 @@ class SectionHeader<T> extends StatelessWidget {
|
|||
),
|
||||
TextSpan(
|
||||
text: title,
|
||||
style: AStyles.unknownTitleText,
|
||||
style: _headerTextStyle(context),
|
||||
),
|
||||
if (trailing != null)
|
||||
WidgetSpan(
|
||||
|
@ -152,7 +152,7 @@ class SectionHeader<T> extends StatelessWidget {
|
|||
if (hasTrailing) TextSpan(text: '\u200A' * 17),
|
||||
TextSpan(
|
||||
text: title,
|
||||
style: AStyles.unknownTitleText,
|
||||
style: _headerTextStyle(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -163,6 +163,12 @@ class SectionHeader<T> extends StatelessWidget {
|
|||
paragraph.dispose();
|
||||
return height;
|
||||
}
|
||||
|
||||
static TextStyle _headerTextStyle(BuildContext context) {
|
||||
// specify `height` for accurate paragraph height measurement
|
||||
final defaultTextHeight = DefaultTextStyle.of(context).style.height;
|
||||
return AStyles.unknownTitleText.copyWith(height: defaultTextHeight);
|
||||
}
|
||||
}
|
||||
|
||||
class _SectionSelectableLeading<T> extends StatelessWidget {
|
||||
|
|
|
@ -39,7 +39,7 @@ class CaptionedButton extends StatefulWidget {
|
|||
var height = width;
|
||||
if (showCaption) {
|
||||
final paragraph = RenderParagraph(
|
||||
TextSpan(text: text, style: CaptionedButtonText.textStyle(context)),
|
||||
TextSpan(text: text, style: CaptionedButtonText._textStyle(context)),
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaler: MediaQuery.textScalerOf(context),
|
||||
maxLines: CaptionedButtonText.maxLines,
|
||||
|
@ -112,7 +112,7 @@ class _CaptionedButtonState extends State<CaptionedButton> {
|
|||
child: ValueListenableBuilder<bool>(
|
||||
valueListenable: _focusedNotifier,
|
||||
builder: (context, focused, child) {
|
||||
final style = CaptionedButtonText.textStyle(context);
|
||||
final style = CaptionedButtonText._textStyle(context);
|
||||
return AnimatedDefaultTextStyle(
|
||||
style: focused
|
||||
? style.copyWith(
|
||||
|
@ -176,5 +176,9 @@ class CaptionedButtonText extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
static TextStyle textStyle(BuildContext context) => Theme.of(context).textTheme.bodySmall!;
|
||||
static TextStyle _textStyle(BuildContext context) {
|
||||
// specify `height` for accurate paragraph height measurement
|
||||
final defaultTextHeight = DefaultTextStyle.of(context).style.height;
|
||||
return Theme.of(context).textTheme.bodySmall!.copyWith(height: defaultTextHeight);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:aves/services/common/services.dart';
|
|||
import 'package:aves/services/geocoding_service.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/utils/debouncer.dart';
|
||||
import 'package:aves/widgets/common/basic/scaffold.dart';
|
||||
|
@ -280,7 +279,6 @@ class _AddressRowState extends State<_AddressRow> {
|
|||
builder: (context, addressLine, child) {
|
||||
return Text(
|
||||
addressLine ?? AText.valueNotAvailable,
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
|
@ -331,7 +329,6 @@ class _CoordinateRow extends StatelessWidget {
|
|||
Expanded(
|
||||
child: Text(
|
||||
location != null ? settings.coordinateFormat.format(context, location!) : AText.valueNotAvailable,
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'package:aves/model/filters/filters.dart';
|
|||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/theme/format.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/utils/android_file_utils.dart';
|
||||
import 'package:aves/utils/file_utils.dart';
|
||||
|
@ -107,7 +106,6 @@ class FilterListDetails<T extends CollectionFilter> extends StatelessWidget {
|
|||
child: Text(
|
||||
dateText,
|
||||
style: detailsTheme.captionStyle,
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
|
@ -158,7 +156,6 @@ class FilterListDetails<T extends CollectionFilter> extends StatelessWidget {
|
|||
Text(
|
||||
'${l10n.itemCount(source.count(filter))} • ${formatFileSize(locale, source.size(filter))}',
|
||||
style: detailsTheme.captionStyle,
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/theme/format.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -34,8 +33,10 @@ class FilterListDetailsTheme extends StatelessWidget {
|
|||
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
final titleStyleBase = textTheme.bodyMedium!;
|
||||
final titleStyle = titleStyleBase.copyWith(fontSize: textScaler.scale(titleStyleBase.fontSize!));
|
||||
final captionStyle = textTheme.bodySmall!;
|
||||
// specify `height` for accurate paragraph height measurement
|
||||
final defaultTextHeight = DefaultTextStyle.of(context).style.height;
|
||||
final titleStyle = titleStyleBase.copyWith(fontSize: textScaler.scale(titleStyleBase.fontSize!), height: defaultTextHeight);
|
||||
final captionStyle = textTheme.bodySmall!.copyWith(height: defaultTextHeight);
|
||||
|
||||
final titleIconSize = textScaler.scale(AvesFilterChip.iconSize);
|
||||
final titleLineHeightParagraph = RenderParagraph(
|
||||
|
@ -50,7 +51,6 @@ class FilterListDetailsTheme extends StatelessWidget {
|
|||
TextSpan(text: formatDateTime(DateTime.now(), locale, use24hour), style: captionStyle),
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaler: textScaler,
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
)..layout(const BoxConstraints(), parentUsesSize: true);
|
||||
final captionLineHeight = captionLineHeightParagraph.getMaxIntrinsicHeight(double.infinity);
|
||||
captionLineHeightParagraph.dispose();
|
||||
|
|
|
@ -5,7 +5,6 @@ import 'package:aves/model/settings/settings.dart';
|
|||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/services/geocoding_service.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
@ -78,7 +77,6 @@ class _MapAddressRowState extends State<MapAddressRow> {
|
|||
TextSpan(text: location),
|
||||
],
|
||||
),
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/theme/format.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/map/info_row.dart';
|
||||
|
@ -35,7 +34,6 @@ class MapDateRow extends StatelessWidget {
|
|||
TextSpan(text: dateText),
|
||||
],
|
||||
),
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
|
|
|
@ -2,7 +2,6 @@ import 'package:aves/model/entry/entry.dart';
|
|||
import 'package:aves/model/entry/extensions/props.dart';
|
||||
import 'package:aves/theme/format.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/viewer/multipage/controller.dart';
|
||||
|
@ -37,8 +36,8 @@ class OverlayDateRow extends StatelessWidget {
|
|||
children: [
|
||||
DecoratedIcon(AIcons.date, size: ViewerDetailOverlayContent.iconSize, shadows: ViewerDetailOverlayContent.shadows(context)),
|
||||
const SizedBox(width: ViewerDetailOverlayContent.iconPadding),
|
||||
Expanded(flex: 3, child: Text(dateText, strutStyle: AStyles.overflowStrut)),
|
||||
Expanded(flex: 2, child: Text(resolutionText, strutStyle: AStyles.overflowStrut)),
|
||||
Expanded(flex: 3, child: Text(dateText)),
|
||||
Expanded(flex: 2, child: Text(resolutionText)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/widgets/viewer/overlay/details/details.dart';
|
||||
import 'package:decorated_icon/decorated_icon.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -31,7 +30,6 @@ class OverlayDescriptionRow extends StatelessWidget {
|
|||
TextSpan(text: description),
|
||||
],
|
||||
),
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'package:aves/model/entry/extensions/location.dart';
|
|||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/widgets/viewer/overlay/details/details.dart';
|
||||
import 'package:decorated_icon/decorated_icon.dart';
|
||||
|
@ -33,7 +32,7 @@ class OverlayLocationRow extends AnimatedWidget {
|
|||
children: [
|
||||
DecoratedIcon(AIcons.location, size: ViewerDetailOverlayContent.iconSize, shadows: ViewerDetailOverlayContent.shadows(context)),
|
||||
const SizedBox(width: ViewerDetailOverlayContent.iconPadding),
|
||||
Expanded(child: Text(location ?? AText.valueNotAvailable, strutStyle: AStyles.overflowStrut)),
|
||||
Expanded(child: Text(location ?? AText.valueNotAvailable)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/multipage.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/widgets/viewer/multipage/controller.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -25,12 +24,12 @@ class OverlayPositionTitleRow extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Text toText({String? pagePosition}) => Text(
|
||||
[
|
||||
if (collectionPosition != null) collectionPosition,
|
||||
if (pagePosition != null) pagePosition,
|
||||
if (title != null) '${Unicode.FSI}$title${Unicode.PDI}',
|
||||
].join(AText.separator),
|
||||
strutStyle: AStyles.overflowStrut);
|
||||
[
|
||||
if (collectionPosition != null) collectionPosition,
|
||||
if (pagePosition != null) pagePosition,
|
||||
if (title != null) '${Unicode.FSI}$title${Unicode.PDI}',
|
||||
].join(AText.separator),
|
||||
);
|
||||
|
||||
if (multiPageController == null) return toText();
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/viewer/overlay/details/details.dart';
|
||||
|
@ -57,7 +56,6 @@ class OverlayRatingTagsRow extends AnimatedWidget {
|
|||
]
|
||||
],
|
||||
),
|
||||
strutStyle: AStyles.overflowStrut,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:aves/model/metadata/overlay.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/theme/styles.dart';
|
||||
import 'package:aves/theme/text.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/viewer/overlay/details/details.dart';
|
||||
|
@ -33,10 +32,10 @@ class OverlayShootingRow extends StatelessWidget {
|
|||
children: [
|
||||
DecoratedIcon(AIcons.shooting, size: ViewerDetailOverlayContent.iconSize, shadows: ViewerDetailOverlayContent.shadows(context)),
|
||||
const SizedBox(width: ViewerDetailOverlayContent.iconPadding),
|
||||
Expanded(child: Text(apertureText, strutStyle: AStyles.overflowStrut)),
|
||||
Expanded(child: Text(details.exposureTime ?? AText.valueNotAvailable, strutStyle: AStyles.overflowStrut)),
|
||||
Expanded(child: Text(focalLengthText, strutStyle: AStyles.overflowStrut)),
|
||||
Expanded(child: Text(isoText, strutStyle: AStyles.overflowStrut)),
|
||||
Expanded(child: Text(apertureText)),
|
||||
Expanded(child: Text(details.exposureTime ?? AText.valueNotAvailable)),
|
||||
Expanded(child: Text(focalLengthText)),
|
||||
Expanded(child: Text(isoText)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue