apply text scale factor
This commit is contained in:
parent
033dd84282
commit
810f32d542
10 changed files with 85 additions and 68 deletions
|
@ -27,8 +27,8 @@ class OutlinedText extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
if (leadingBuilder != null)
|
||||
WidgetSpan(
|
||||
|
@ -52,8 +52,8 @@ class OutlinedText extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
if (leadingBuilder != null)
|
||||
WidgetSpan(
|
||||
|
|
|
@ -34,7 +34,7 @@ class AndroidFileUtils {
|
|||
|
||||
StorageVolume getStorageVolume(String path) => storageVolumes.firstWhere((v) => path.startsWith(v.path), orElse: () => null);
|
||||
|
||||
bool isOnRemovableStorage(String path) => getStorageVolume(path).isRemovable;
|
||||
bool isOnRemovableStorage(String path) => getStorageVolume(path)?.isRemovable ?? false;
|
||||
|
||||
AlbumType getAlbumType(String albumDirectory) {
|
||||
if (albumDirectory != null) {
|
||||
|
|
|
@ -17,8 +17,8 @@ class AboutPage extends StatelessWidget {
|
|||
delegate: SliverChildListDelegate(
|
||||
[
|
||||
Center(
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
const TextSpan(text: 'Made with ❤️ and '),
|
||||
WidgetSpan(
|
||||
|
|
|
@ -59,11 +59,12 @@ class _LicensesState extends State<Licenses> {
|
|||
padding: const EdgeInsetsDirectional.only(start: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'Open-source licenses',
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Open-Source Licenses',
|
||||
style: Theme.of(context).textTheme.headline6.copyWith(fontFamily: 'Concourse Caps'),
|
||||
),
|
||||
const Spacer(),
|
||||
),
|
||||
PopupMenuButton<LicenseSort>(
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
|
|
|
@ -67,8 +67,9 @@ class SectionHeader extends StatelessWidget {
|
|||
}
|
||||
|
||||
// TODO TLAD cache header extent computation?
|
||||
static double computeHeaderHeight(CollectionSource source, dynamic sectionKey, double scrollableWidth) {
|
||||
static double computeHeaderHeight(BuildContext context, CollectionSource source, dynamic sectionKey, double scrollableWidth) {
|
||||
var headerExtent = 0.0;
|
||||
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
||||
if (sectionKey is String) {
|
||||
// only compute height for album headers, as they're the only likely ones to split on multiple lines
|
||||
final hasLeading = androidFileUtils.getAlbumType(sectionKey) != AlbumType.regular;
|
||||
|
@ -83,7 +84,7 @@ class SectionHeader extends StatelessWidget {
|
|||
TextSpan(
|
||||
text: '\u200A' * (hasLeading ? 23 : 1),
|
||||
// force a higher first line to match leading icon/selector dimension
|
||||
style: const TextStyle(height: 2.3),
|
||||
style: TextStyle(height: 2.3 * textScaleFactor),
|
||||
), // 23 hair spaces match a width of 40.0
|
||||
if (hasTrailing)
|
||||
TextSpan(text: '\u200A' * 17),
|
||||
|
@ -94,10 +95,11 @@ class SectionHeader extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaleFactor: textScaleFactor,
|
||||
)..layout(BoxConstraints(maxWidth: maxWidth), parentUsesSize: true);
|
||||
headerExtent = para.getMaxIntrinsicHeight(maxWidth);
|
||||
}
|
||||
headerExtent = max(headerExtent, TitleSectionHeader.leadingDimension) + TitleSectionHeader.padding.vertical;
|
||||
headerExtent = max(headerExtent, TitleSectionHeader.leadingDimension * textScaleFactor) + TitleSectionHeader.padding.vertical;
|
||||
return headerExtent;
|
||||
}
|
||||
}
|
||||
|
@ -127,8 +129,8 @@ class TitleSectionHeader extends StatelessWidget {
|
|||
alignment: AlignmentDirectional.centerStart,
|
||||
padding: padding,
|
||||
constraints: const BoxConstraints(minHeight: leadingDimension),
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
alignment: widgetSpanAlignment,
|
||||
|
|
|
@ -44,7 +44,7 @@ class SectionedListLayoutProvider extends StatelessWidget {
|
|||
final sectionEntryCount = sections[sectionKey].length;
|
||||
final sectionChildCount = 1 + (sectionEntryCount / columnCount).ceil();
|
||||
|
||||
final headerExtent = showHeaders ? SectionHeader.computeHeaderHeight(source, sectionKey, scrollableWidth) : 0.0;
|
||||
final headerExtent = showHeaders ? SectionHeader.computeHeaderHeight(context, source, sectionKey, scrollableWidth) : 0.0;
|
||||
|
||||
final sectionFirstIndex = currentIndex;
|
||||
currentIndex += sectionChildCount;
|
||||
|
|
|
@ -50,10 +50,13 @@ class _AppDrawerState extends State<AppDrawer> {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: Wrap(
|
||||
spacing: 16,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
const AvesLogo(size: 64),
|
||||
const SizedBox(width: 16),
|
||||
const Text(
|
||||
'Aves',
|
||||
style: TextStyle(
|
||||
|
@ -63,6 +66,7 @@ class _AppDrawerState extends State<AppDrawer> {
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -28,7 +28,7 @@ class MenuRow extends StatelessWidget {
|
|||
Icon(icon),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
Text(text),
|
||||
Expanded(child: Text(text)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ class FilterTable extends StatelessWidget {
|
|||
return c != 0 ? c : compareAsciiUpperCase(kv1.key, kv2.key);
|
||||
});
|
||||
|
||||
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
||||
final lineHeight = 16 * textScaleFactor;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.only(start: AvesFilterChip.buttonBorderWidth / 2 + 6, end: 8),
|
||||
child: LayoutBuilder(
|
||||
|
@ -55,11 +58,11 @@ class FilterTable extends StatelessWidget {
|
|||
if (showPercentIndicator)
|
||||
LinearPercentIndicator(
|
||||
percent: percent,
|
||||
lineHeight: 16,
|
||||
lineHeight: lineHeight,
|
||||
backgroundColor: Colors.white24,
|
||||
progressColor: stringToColor(label),
|
||||
animation: true,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: EdgeInsets.symmetric(horizontal: lineHeight),
|
||||
center: Text(NumberFormat.percentPattern().format(percent)),
|
||||
),
|
||||
Text(
|
||||
|
|
|
@ -51,41 +51,46 @@ class StatsPage extends StatelessWidget {
|
|||
if (collection.isEmpty) {
|
||||
child = const EmptyContent();
|
||||
} else {
|
||||
final catalogued = entries.where((entry) => entry.isCatalogued);
|
||||
final withGps = catalogued.where((entry) => entry.hasGps);
|
||||
final withGpsPercent = withGps.length / collection.entryCount;
|
||||
final byMimeTypes = groupBy(entries, (entry) => entry.mimeType).map<String, int>((k, v) => MapEntry(k, v.length));
|
||||
final imagesByMimeTypes = Map.fromEntries(byMimeTypes.entries.where((kv) => kv.key.startsWith('image/')));
|
||||
final videoByMimeTypes = Map.fromEntries(byMimeTypes.entries.where((kv) => kv.key.startsWith('video/')));
|
||||
child = ListView(
|
||||
children: [
|
||||
Wrap(
|
||||
final mimeDonuts = Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
_buildMimeDonut(context, (sum) => Intl.plural(sum, one: 'image', other: 'images'), imagesByMimeTypes),
|
||||
_buildMimeDonut(context, (sum) => Intl.plural(sum, one: 'video', other: 'videos'), videoByMimeTypes),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
);
|
||||
|
||||
final catalogued = entries.where((entry) => entry.isCatalogued);
|
||||
final withGps = catalogued.where((entry) => entry.hasGps);
|
||||
final withGpsPercent = withGps.length / collection.entryCount;
|
||||
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
||||
final lineHeight = 16 * textScaleFactor;
|
||||
final locationIndicator = Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
LinearPercentIndicator(
|
||||
percent: withGpsPercent,
|
||||
lineHeight: 16,
|
||||
lineHeight: lineHeight,
|
||||
backgroundColor: Colors.white24,
|
||||
progressColor: Theme.of(context).accentColor,
|
||||
animation: true,
|
||||
leading: const Icon(AIcons.location),
|
||||
// right padding to match leading, so that inside label is aligned with outside label below
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(right: 24),
|
||||
padding: EdgeInsets.symmetric(horizontal: lineHeight) + const EdgeInsets.only(right: 24),
|
||||
center: Text(NumberFormat.percentPattern().format(withGpsPercent)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text('${withGps.length} ${Intl.plural(withGps.length, one: 'item', other: 'items')} with location'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
child = ListView(
|
||||
children: [
|
||||
mimeDonuts,
|
||||
locationIndicator,
|
||||
..._buildTopFilters('Top Countries', entryCountPerCountry, (s) => LocationFilter(LocationLevel.country, s)),
|
||||
..._buildTopFilters('Top Places', entryCountPerPlace, (s) => LocationFilter(LocationLevel.place, s)),
|
||||
..._buildTopFilters('Top Tags', entryCountPerTag, (s) => TagFilter(s)),
|
||||
|
@ -132,8 +137,10 @@ class StatsPage extends StatelessWidget {
|
|||
];
|
||||
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
||||
final minWidth = mimeDonutMinWidth * textScaleFactor;
|
||||
final availableWidth = constraints.maxWidth;
|
||||
final dim = max(mimeDonutMinWidth, availableWidth / (availableWidth > 4 * mimeDonutMinWidth ? 4 : 2));
|
||||
final dim = max(minWidth, availableWidth / (availableWidth > 4 * minWidth ? 4 : (availableWidth > 2 * minWidth ? 2 : 1)));
|
||||
|
||||
final donut = Container(
|
||||
width: dim,
|
||||
|
@ -161,11 +168,8 @@ class StatsPage extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: seriesData
|
||||
.map((kv) => RichText(
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
maxLines: 1,
|
||||
text: TextSpan(
|
||||
.map((kv) => Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
|
@ -178,6 +182,9 @@ class StatsPage extends StatelessWidget {
|
|||
TextSpan(text: '${kv.value}', style: const TextStyle(color: Colors.white70)),
|
||||
],
|
||||
),
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
maxLines: 1,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
|
@ -186,7 +193,7 @@ class StatsPage extends StatelessWidget {
|
|||
donut,
|
||||
legend,
|
||||
];
|
||||
return availableWidth > mimeDonutMinWidth * 2
|
||||
return availableWidth > minWidth * 2
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: children,
|
||||
|
|
Loading…
Reference in a new issue