nc-photos/app/lib/widget/slideshow_viewer/timeline.dart
2024-08-10 02:10:37 +08:00

116 lines
3 KiB
Dart

part of '../slideshow_viewer.dart';
class _Timeline extends StatefulWidget {
const _Timeline();
@override
State<StatefulWidget> createState() => _TimelineState();
static const width = 96.0;
}
class _TimelineState extends State<_Timeline> {
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MultiBlocListener(
listeners: [
_BlocListenerT(
selector: (state) => state.page,
listener: (context, page) {
if (_lastInteraction == null ||
clock.now().difference(_lastInteraction!) >
const Duration(seconds: 10)) {
_controller.animateTo(
page * _Timeline.width,
duration: k.animationDurationShort,
curve: Curves.easeOut,
);
}
},
),
],
child: Container(
width: _Timeline.width,
color: Colors.black.withOpacity(.65),
child: NotificationListener<UserScrollNotification>(
onNotification: (notification) {
_lastInteraction = clock.now();
return false;
},
child: ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(
scrollbars: false,
overscroll: false,
),
child: ListView.builder(
scrollDirection: Axis.vertical,
controller: _controller,
itemCount: context.bloc.pageCount,
itemBuilder: (context, i) => _BlocSelector<int>(
selector: (state) => state.page,
builder: (context, page) => _TimelineItem(
index: i,
file: context.bloc.getFileByPageIndex(i),
isSelected: i == page,
),
),
),
),
),
),
);
}
late final _controller = ScrollController();
DateTime? _lastInteraction;
}
class _TimelineItem extends StatelessWidget {
const _TimelineItem({
required this.index,
required this.file,
required this.isSelected,
});
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
padding: const EdgeInsets.all(8),
color: isSelected
? Theme.of(context).colorScheme.secondaryContainer
: Colors.transparent,
child: PhotoListImage(
account: context.bloc.account,
previewUrl: NetworkRectThumbnail.imageUrlForFile(
context.bloc.account,
file,
),
),
),
if (!isSelected)
Positioned.fill(
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {
context.addEvent(_RequestPage(index));
},
),
),
),
],
);
}
final int index;
final FileDescriptor file;
final bool isSelected;
}