140 lines
4.7 KiB
Dart
140 lines
4.7 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:aves/model/collection_lens.dart';
|
|
import 'package:aves/model/collection_source.dart';
|
|
import 'package:aves/utils/android_file_utils.dart';
|
|
import 'package:aves/utils/constants.dart';
|
|
import 'package:aves/widgets/album/grid/header_album.dart';
|
|
import 'package:aves/widgets/album/grid/header_date.dart';
|
|
import 'package:aves/widgets/common/fx/outlined_text.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
|
|
class SectionHeader extends StatelessWidget {
|
|
final CollectionLens collection;
|
|
final dynamic sectionKey;
|
|
|
|
const SectionHeader({
|
|
Key key,
|
|
@required this.collection,
|
|
@required this.sectionKey,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget header;
|
|
switch (collection.sortFactor) {
|
|
case SortFactor.date:
|
|
if (collection.sortFactor == SortFactor.date) {
|
|
switch (collection.groupFactor) {
|
|
case GroupFactor.album:
|
|
header = _buildAlbumSectionHeader();
|
|
break;
|
|
case GroupFactor.month:
|
|
header = MonthSectionHeader(key: ValueKey(sectionKey), date: sectionKey as DateTime);
|
|
break;
|
|
case GroupFactor.day:
|
|
header = DaySectionHeader(key: ValueKey(sectionKey), date: sectionKey as DateTime);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case SortFactor.size:
|
|
break;
|
|
case SortFactor.name:
|
|
header = _buildAlbumSectionHeader();
|
|
break;
|
|
}
|
|
return header != null
|
|
? IgnorePointer(
|
|
child: header,
|
|
)
|
|
: const SizedBox.shrink();
|
|
}
|
|
|
|
Widget _buildAlbumSectionHeader() {
|
|
final folderPath = sectionKey as String;
|
|
return AlbumSectionHeader(
|
|
key: ValueKey(folderPath),
|
|
folderPath: folderPath,
|
|
albumName: collection.source.getUniqueAlbumName(folderPath),
|
|
);
|
|
}
|
|
|
|
// TODO TLAD cache header extent computation?
|
|
static double computeHeaderHeight(CollectionSource source, dynamic sectionKey, double scrollableWidth) {
|
|
var headerExtent = 0.0;
|
|
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.Default;
|
|
final hasTrailing = androidFileUtils.isOnSD(sectionKey);
|
|
final text = source.getUniqueAlbumName(sectionKey);
|
|
final maxWidth = scrollableWidth - TitleSectionHeader.padding.horizontal;
|
|
final para = RenderParagraph(
|
|
TextSpan(
|
|
children: [
|
|
if (hasLeading)
|
|
// `RenderParagraph` fails to lay out `WidgetSpan` offscreen as of Flutter v1.17.0
|
|
// so we use a hair space times a magic number to match leading width
|
|
TextSpan(text: '\u200A' * 23), // 23 hair spaces match a width of 40.0
|
|
if (hasTrailing)
|
|
TextSpan(text: '\u200A' * 17),
|
|
TextSpan(
|
|
text: text,
|
|
style: Constants.titleTextStyle,
|
|
),
|
|
],
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
)..layout(BoxConstraints(maxWidth: maxWidth), parentUsesSize: true);
|
|
headerExtent = para.getMaxIntrinsicHeight(maxWidth);
|
|
}
|
|
headerExtent = max(headerExtent, TitleSectionHeader.leadingDimension) + TitleSectionHeader.padding.vertical;
|
|
return headerExtent;
|
|
}
|
|
}
|
|
|
|
class TitleSectionHeader extends StatelessWidget {
|
|
final Widget leading, trailing;
|
|
final String title;
|
|
|
|
const TitleSectionHeader({
|
|
Key key,
|
|
this.leading,
|
|
this.title,
|
|
this.trailing,
|
|
}) : super(key: key);
|
|
|
|
static const leadingDimension = 32.0;
|
|
static const leadingPadding = EdgeInsets.only(right: 8, bottom: 4);
|
|
static const trailingPadding = EdgeInsets.only(left: 8, bottom: 4);
|
|
static const padding = EdgeInsets.all(16);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
alignment: AlignmentDirectional.centerStart,
|
|
padding: padding,
|
|
constraints: const BoxConstraints(minHeight: leadingDimension),
|
|
child: OutlinedText(
|
|
leadingBuilder: leading != null
|
|
? (context, isShadow) => Container(
|
|
padding: leadingPadding,
|
|
width: leadingDimension,
|
|
height: leadingDimension,
|
|
child: isShadow ? null : leading,
|
|
)
|
|
: null,
|
|
text: title,
|
|
trailingBuilder: trailing != null
|
|
? (context, isShadow) => Container(
|
|
padding: trailingPadding,
|
|
child: isShadow ? null : trailing,
|
|
)
|
|
: null,
|
|
style: Constants.titleTextStyle,
|
|
outlineWidth: 2,
|
|
),
|
|
);
|
|
}
|
|
}
|