mirror of
https://github.com/Myzel394/quid_faciam_hodie.git
synced 2025-06-18 23:35:25 +02:00
improvements
This commit is contained in:
parent
8409939825
commit
13ea760cb8
68
lib/models/timeline.dart
Normal file
68
lib/models/timeline.dart
Normal file
@ -0,0 +1,68 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:share_location/foreign_types/memory.dart';
|
||||
import 'package:share_location/models/memory_pack.dart';
|
||||
|
||||
class TimelineModel extends ChangeNotifier {
|
||||
final Map<String, MemoryPack> _timeline;
|
||||
|
||||
TimelineModel({
|
||||
Map<String, MemoryPack>? timeline,
|
||||
}) : _timeline = timeline ?? {};
|
||||
|
||||
Map<String, MemoryPack> get values => _timeline;
|
||||
|
||||
static TimelineModel fromMemoriesList(
|
||||
final List<Memory> memories,
|
||||
) {
|
||||
final map = <String, List<Memory>>{};
|
||||
|
||||
for (final memory in memories) {
|
||||
final date = DateFormat('yyyy-MM-dd').format(memory.creationDate);
|
||||
if (map.containsKey(date)) {
|
||||
map[date]!.add(memory);
|
||||
} else {
|
||||
map[date] = [memory];
|
||||
}
|
||||
}
|
||||
|
||||
final data = Map.fromEntries(
|
||||
map.entries.map(
|
||||
(entry) => MapEntry<String, MemoryPack>(
|
||||
entry.key,
|
||||
MemoryPack(entry.value),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return TimelineModel(
|
||||
timeline: data,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timeline.values.forEach((memoryPack) {
|
||||
memoryPack.dispose();
|
||||
});
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void removeEmptyDates() {
|
||||
final previousLength = _timeline.length;
|
||||
|
||||
_timeline.removeWhere((key, value) => value.memories.isEmpty);
|
||||
|
||||
final newLength = _timeline.length;
|
||||
|
||||
if (previousLength != newLength) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
DateTime dateAtIndex(final int index) =>
|
||||
DateTime.parse(_timeline.keys.elementAt(index));
|
||||
|
||||
MemoryPack atIndex(final int index) => _timeline.values.elementAt(index);
|
||||
}
|
@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:share_location/controllers/status_controller.dart';
|
||||
import 'package:share_location/enums.dart';
|
||||
import 'package:share_location/foreign_types/memory.dart';
|
||||
import 'package:share_location/models/memory_pack.dart';
|
||||
import 'package:share_location/models/timeline_overlay.dart';
|
||||
import 'package:share_location/widgets/status.dart';
|
||||
|
||||
@ -59,6 +60,7 @@ class _MemorySlideState extends State<MemorySlide>
|
||||
|
||||
void initializeAnimation(final Duration duration) {
|
||||
final timelineOverlay = context.read<TimelineOverlay>();
|
||||
final memoryPack = context.read<MemoryPack>();
|
||||
|
||||
this.duration = duration;
|
||||
|
||||
@ -72,7 +74,8 @@ class _MemorySlideState extends State<MemorySlide>
|
||||
}
|
||||
|
||||
if (controller!.done) {
|
||||
timelineOverlay.setState(TimelineState.completed);
|
||||
timelineOverlay.reset();
|
||||
memoryPack.next();
|
||||
}
|
||||
}, ['done']);
|
||||
|
||||
@ -81,10 +84,10 @@ class _MemorySlideState extends State<MemorySlide>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<TimelineOverlay>(
|
||||
builder: (context, overlayController, _) => Status(
|
||||
return Consumer<MemoryPack>(
|
||||
builder: (context, memoryPack, _) => Status(
|
||||
controller: controller,
|
||||
disabled: !overlayController.showOverlay,
|
||||
disabled: memoryPack.paused,
|
||||
child: MemoryView(
|
||||
creationDate: widget.memory.creationDate,
|
||||
location: widget.memory.location,
|
||||
@ -99,17 +102,17 @@ class _MemorySlideState extends State<MemorySlide>
|
||||
if (mounted) {
|
||||
initializeAnimation(controller.value.duration);
|
||||
|
||||
overlayController.addListener(() {
|
||||
memoryPack.addListener(() {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (overlayController.state == TimelineState.playing) {
|
||||
controller.play();
|
||||
} else {
|
||||
if (memoryPack.paused) {
|
||||
controller.pause();
|
||||
} else {
|
||||
controller.play();
|
||||
}
|
||||
}, ['state']);
|
||||
}, ['paused']);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -13,12 +13,14 @@ class TimelinePage extends StatefulWidget {
|
||||
final DateTime date;
|
||||
final VoidCallback onPreviousTimeline;
|
||||
final VoidCallback onNextTimeline;
|
||||
final VoidCallback onMemoryRemoved;
|
||||
|
||||
const TimelinePage({
|
||||
Key? key,
|
||||
required this.date,
|
||||
required this.onPreviousTimeline,
|
||||
required this.onNextTimeline,
|
||||
required this.onMemoryRemoved,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -48,6 +50,18 @@ class _TimelinePageState extends State<TimelinePage> {
|
||||
}
|
||||
}, ['state']);
|
||||
|
||||
memoryPack.addListener(() {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (memoryPack.paused) {
|
||||
timelineOverlayController.hideOverlay();
|
||||
} else {
|
||||
timelineOverlayController.restoreOverlay();
|
||||
}
|
||||
}, ['state']);
|
||||
|
||||
memoryPack.addListener(() {
|
||||
if (!mounted) {
|
||||
return;
|
||||
@ -81,7 +95,6 @@ class _TimelinePageState extends State<TimelinePage> {
|
||||
final memoryPack = context.read<MemoryPack>();
|
||||
|
||||
memoryPack.pause();
|
||||
timelineOverlayController.hideOverlay();
|
||||
|
||||
await showModalBottomSheet(
|
||||
context: context,
|
||||
@ -98,16 +111,15 @@ class _TimelinePageState extends State<TimelinePage> {
|
||||
|
||||
memoryPack.removeCurrentMemory();
|
||||
memoryPack.resume();
|
||||
timelineOverlayController.restoreOverlay();
|
||||
|
||||
widget.onMemoryRemoved();
|
||||
},
|
||||
onTapDown: (_) {
|
||||
final memoryPack = context.read<MemoryPack>();
|
||||
|
||||
memoryPack.pause();
|
||||
|
||||
overlayRemover = Timer(
|
||||
const Duration(milliseconds: 200),
|
||||
timelineOverlayController.hideOverlay,
|
||||
memoryPack.pause,
|
||||
);
|
||||
},
|
||||
onTapUp: (_) {
|
||||
@ -115,14 +127,11 @@ class _TimelinePageState extends State<TimelinePage> {
|
||||
|
||||
overlayRemover?.cancel();
|
||||
memoryPack.resume();
|
||||
timelineOverlayController.restoreOverlay();
|
||||
},
|
||||
onTapCancel: () {
|
||||
final memoryPack = context.read<MemoryPack>();
|
||||
|
||||
overlayRemover?.cancel();
|
||||
|
||||
timelineOverlayController.restoreOverlay();
|
||||
memoryPack.resume();
|
||||
},
|
||||
onHorizontalDragEnd: (details) {
|
||||
@ -146,34 +155,30 @@ class _TimelinePageState extends State<TimelinePage> {
|
||||
},
|
||||
child: ChangeNotifierProvider<TimelineOverlay>(
|
||||
create: (_) => timelineOverlayController,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: <Widget>[
|
||||
Consumer<MemoryPack>(
|
||||
builder: (_, memoryPack, __) {
|
||||
return PageView.builder(
|
||||
controller: pageController,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemBuilder: (_, index) => MemorySlide(
|
||||
key: Key(memoryPack.memories[index].filename),
|
||||
memory: memoryPack.memories[index],
|
||||
),
|
||||
itemCount: memoryPack.memories.length,
|
||||
);
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: LARGE_SPACE,
|
||||
left: MEDIUM_SPACE,
|
||||
right: MEDIUM_SPACE,
|
||||
child: Consumer<MemoryPack>(
|
||||
builder: (_, memoryPack, __) => Stack(
|
||||
fit: StackFit.expand,
|
||||
children: <Widget>[
|
||||
PageView.builder(
|
||||
controller: pageController,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemBuilder: (_, index) => MemorySlide(
|
||||
key: Key(memoryPack.memories[index].filename),
|
||||
memory: memoryPack.memories[index],
|
||||
),
|
||||
itemCount: memoryPack.memories.length,
|
||||
),
|
||||
child: Consumer<TimelineOverlay>(
|
||||
builder: (context, overlayController, _) => AnimatedOpacity(
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: LARGE_SPACE,
|
||||
left: MEDIUM_SPACE,
|
||||
right: MEDIUM_SPACE,
|
||||
),
|
||||
child: AnimatedOpacity(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.linearToEaseOut,
|
||||
opacity: overlayController.showOverlay ? 1.0 : 0.0,
|
||||
opacity: memoryPack.paused ? 0.0 : 1.0,
|
||||
child: Text(
|
||||
DateFormat('dd. MMMM yyyy').format(widget.date),
|
||||
textAlign: TextAlign.center,
|
||||
@ -181,8 +186,26 @@ class _TimelinePageState extends State<TimelinePage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Positioned(
|
||||
right: SMALL_SPACE,
|
||||
bottom: SMALL_SPACE * 2,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: SMALL_SPACE),
|
||||
child: AnimatedOpacity(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.linearToEaseOut,
|
||||
opacity: memoryPack.paused ? 0.0 : 1.0,
|
||||
child: Consumer<MemoryPack>(
|
||||
builder: (_, memoryPack, __) => Text(
|
||||
'${memoryPack.currentMemoryIndex + 1}/${memoryPack.memories.length}',
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,8 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:share_location/foreign_types/memory.dart';
|
||||
import 'package:share_location/models/memory_pack.dart';
|
||||
import 'package:share_location/models/timeline.dart';
|
||||
import 'package:share_location/utils/loadable.dart';
|
||||
import 'package:share_location/widgets/timeline_page.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
@ -20,7 +19,7 @@ class TimelineScroll extends StatefulWidget {
|
||||
|
||||
class _TimelineScrollState extends State<TimelineScroll> with Loadable {
|
||||
final pageController = PageController();
|
||||
Map<String, MemoryPack>? timeline;
|
||||
TimelineModel? timeline;
|
||||
|
||||
@override
|
||||
initState() {
|
||||
@ -28,7 +27,18 @@ class _TimelineScrollState extends State<TimelineScroll> with Loadable {
|
||||
loadTimeline();
|
||||
}
|
||||
|
||||
@override
|
||||
dispose() {
|
||||
pageController.dispose();
|
||||
|
||||
timeline?.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> loadTimeline() async {
|
||||
timeline?.dispose();
|
||||
|
||||
final response = await supabase
|
||||
.from('memories')
|
||||
.select()
|
||||
@ -36,35 +46,16 @@ class _TimelineScrollState extends State<TimelineScroll> with Loadable {
|
||||
.execute();
|
||||
final memories = List<Memory>.from(
|
||||
List<Map<String, dynamic>>.from(response.data).map(Memory.parse));
|
||||
final timelineMapped = convertMemoriesToTimeline(memories);
|
||||
|
||||
setState(() {
|
||||
timeline = timelineMapped;
|
||||
timeline = TimelineModel.fromMemoriesList(memories);
|
||||
});
|
||||
}
|
||||
|
||||
static Map<String, MemoryPack> convertMemoriesToTimeline(
|
||||
final List<Memory> memories,
|
||||
) {
|
||||
final map = <String, List<Memory>>{};
|
||||
|
||||
for (final memory in memories) {
|
||||
final date = DateFormat('yyyy-MM-dd').format(memory.creationDate);
|
||||
if (map.containsKey(date)) {
|
||||
map[date]!.add(memory);
|
||||
} else {
|
||||
map[date] = [memory];
|
||||
timeline!.addListener(() {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
return Map.fromEntries(
|
||||
map.entries.map(
|
||||
(entry) => MapEntry<String, MemoryPack>(
|
||||
entry.key,
|
||||
MemoryPack(entry.value),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -79,11 +70,12 @@ class _TimelineScrollState extends State<TimelineScroll> with Loadable {
|
||||
body: PageView.builder(
|
||||
controller: pageController,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: timeline!.length,
|
||||
itemBuilder: (_, index) => ChangeNotifierProvider<MemoryPack>(
|
||||
create: (_) => timeline!.values.elementAt(index),
|
||||
itemCount: timeline!.values.length,
|
||||
itemBuilder: (_, index) => ChangeNotifierProvider.value(
|
||||
value: timeline!.atIndex(index),
|
||||
child: TimelinePage(
|
||||
date: DateTime.parse(timeline!.keys.toList()[index]),
|
||||
date: timeline!.dateAtIndex(index),
|
||||
onMemoryRemoved: () => timeline!.removeEmptyDates(),
|
||||
onNextTimeline: () {
|
||||
pageController.nextPage(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
|
Loading…
x
Reference in New Issue
Block a user