aves/lib/widgets/explorer/crumb_line.dart
2024-12-03 00:25:12 +01:00

122 lines
3.6 KiB
Dart

import 'package:aves/model/settings/settings.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/view/view.dart';
import 'package:aves_model/aves_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class CrumbLine extends StatefulWidget {
final VolumeRelativeDirectory? directory;
final void Function(String path) onTap;
const CrumbLine({
super.key,
required this.directory,
required this.onTap,
});
@override
State<CrumbLine> createState() => _CrumbLineState();
static double getPreferredHeight(TextScaler textScaler) => textScaler.scale(kToolbarHeight);
}
class _CrumbLineState extends State<CrumbLine> {
final ScrollController _scrollController = ScrollController();
VolumeRelativeDirectory? get directory => widget.directory;
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
void didUpdateWidget(covariant CrumbLine oldWidget) {
super.didUpdateWidget(oldWidget);
if ((oldWidget.directory?.relativeDir.length ?? 0) < (widget.directory?.relativeDir.length ?? 0)) {
// scroll to show last crumb
WidgetsBinding.instance.addPostFrameCallback((_) {
final animate = context.read<Settings>().animate;
final extent = _scrollController.position.maxScrollExtent;
if (animate) {
_scrollController.animateTo(
extent,
duration: const Duration(milliseconds: 500),
curve: Curves.easeOutQuad,
);
} else {
_scrollController.jumpTo(extent);
}
});
}
}
@override
Widget build(BuildContext context) {
final _directory = directory;
final parts = <String>[];
if (_directory != null) {
parts.addAll([
_directory.getVolumeDescription(context),
...pContext.split(_directory.relativeDir),
]);
}
final crumbColor = DefaultTextStyle.of(context).style.color;
return ListView.builder(
scrollDirection: Axis.horizontal,
controller: _scrollController,
padding: const EdgeInsets.symmetric(horizontal: 8),
itemBuilder: (context, index) {
Widget _buildText(String text) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(text),
);
if (index >= parts.length) return const SizedBox();
final text = parts[index];
if (index == parts.length - 1) {
return Center(
child: DefaultTextStyle.merge(
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
child: _buildText(text),
),
);
}
return GestureDetector(
onTap: _directory != null
? () {
final path = pContext.joinAll([
_directory.volumePath,
...parts.skip(1).take(index),
]);
widget.onTap(path);
}
: null,
child: Container(
// use a `Container` with a dummy color to make it expand
// so that we can also detect taps around the title `Text`
color: Colors.transparent,
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_buildText(text),
Icon(
AIcons.next,
color: crumbColor,
),
],
),
),
);
},
itemCount: parts.length,
);
}
}