removed TimelineOverlayModel in favor of TimelineModel

This commit is contained in:
Myzel394 2022-08-16 19:52:42 +02:00
parent 518edaff0d
commit c817452d06
5 changed files with 96 additions and 171 deletions

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:property_change_notifier/property_change_notifier.dart'; import 'package:property_change_notifier/property_change_notifier.dart';
@ -19,6 +20,8 @@ class TimelineModel extends PropertyChangeNotifier<String> {
int _memoryIndex = 0; int _memoryIndex = 0;
bool _paused = false; bool _paused = false;
bool _isInitializing = false; bool _isInitializing = false;
bool _showOverlay = true;
Timer? _overlayRemoverTimer;
Map<DateTime, List<Memory>> get values => _timeline; Map<DateTime, List<Memory>> get values => _timeline;
int get length => _timeline.length; int get length => _timeline.length;
@ -26,6 +29,7 @@ class TimelineModel extends PropertyChangeNotifier<String> {
int get memoryIndex => _memoryIndex; int get memoryIndex => _memoryIndex;
bool get paused => _paused; bool get paused => _paused;
bool get isInitializing => _isInitializing; bool get isInitializing => _isInitializing;
bool get showOverlay => _showOverlay;
DateTime dateAtIndex(final int index) => _timeline.keys.elementAt(index); DateTime dateAtIndex(final int index) => _timeline.keys.elementAt(index);
@ -42,6 +46,9 @@ class TimelineModel extends PropertyChangeNotifier<String> {
static DateTime createDateKey(final DateTime date) => static DateTime createDateKey(final DateTime date) =>
DateTime(date.year, date.month, date.day); DateTime(date.year, date.month, date.day);
void restoreOverlay() => setShowOverlay(true);
void hideOverlay() => setShowOverlay(false);
static Map<DateTime, List<Memory>> mapFromMemoriesList( static Map<DateTime, List<Memory>> mapFromMemoriesList(
final List<Memory> memories, final List<Memory> memories,
) { ) {
@ -76,19 +83,37 @@ class TimelineModel extends PropertyChangeNotifier<String> {
_timeline.values.elementAt(_currentIndex).length - 1, _timeline.values.elementAt(_currentIndex).length - 1,
max(0, index), max(0, index),
); );
resume();
notifyListeners('memoryIndex'); notifyListeners('memoryIndex');
} }
void setPaused(bool paused) { void setPaused(final bool paused) {
_paused = paused; _paused = paused;
_overlayRemoverTimer?.cancel();
if (paused) {
_overlayRemoverTimer = Timer(
const Duration(milliseconds: 600),
hideOverlay,
);
} else {
restoreOverlay();
}
notifyListeners('paused'); notifyListeners('paused');
} }
void setIsInitializing(bool isInitializing) { void setIsInitializing(final bool isInitializing) {
_isInitializing = isInitializing; _isInitializing = isInitializing;
notifyListeners('isInitializing'); notifyListeners('isInitializing');
} }
void setShowOverlay(final bool showOverlay) {
_showOverlay = showOverlay;
notifyListeners('showOverlay');
}
void pause() => setPaused(true); void pause() => setPaused(true);
void resume() => setPaused(false); void resume() => setPaused(false);

View File

@ -1,35 +0,0 @@
import 'package:property_change_notifier/property_change_notifier.dart';
enum TimelineState {
loading,
paused,
playing,
completed,
}
class TimelineOverlayModel extends PropertyChangeNotifier<String> {
bool _showOverlay = true;
TimelineState _state = TimelineState.loading;
bool get showOverlay => _showOverlay;
TimelineState get state => _state;
void hideOverlay() => setShowOverlay(false);
void restoreOverlay() => setShowOverlay(true);
void setShowOverlay(bool showOverlay) {
_showOverlay = showOverlay;
notifyListeners('showOverlay');
}
void setState(TimelineState state) {
_state = state;
notifyListeners('state');
}
void reset() {
_showOverlay = true;
_state = TimelineState.loading;
notifyListeners();
}
}

View File

@ -4,7 +4,6 @@ import 'package:share_location/controllers/status_controller.dart';
import 'package:share_location/enums.dart'; import 'package:share_location/enums.dart';
import 'package:share_location/foreign_types/memory.dart'; import 'package:share_location/foreign_types/memory.dart';
import 'package:share_location/models/timeline.dart'; import 'package:share_location/models/timeline.dart';
import 'package:share_location/models/timeline_overlay.dart';
import 'package:share_location/widgets/status.dart'; import 'package:share_location/widgets/status.dart';
import 'memory.dart'; import 'memory.dart';
@ -34,21 +33,19 @@ class _MemorySlideState extends State<MemorySlide>
void initState() { void initState() {
super.initState(); super.initState();
final timelineOverlay = context.read<TimelineOverlayModel>(); final timeline = context.read<TimelineModel>();
timelineOverlay.addListener(() { timeline.addListener(() {
if (!mounted) { if (!mounted) {
return; return;
} }
switch (timelineOverlay.state) { if (timeline.paused) {
case TimelineState.playing: controller?.stop();
controller?.start(); } else {
break; controller?.start();
default:
controller?.stop();
} }
}); }, ['paused']);
} }
@override @override
@ -59,8 +56,6 @@ class _MemorySlideState extends State<MemorySlide>
} }
void initializeAnimation(final Duration newDuration) { void initializeAnimation(final Duration newDuration) {
final timelineOverlay = context.read<TimelineOverlayModel>();
duration = newDuration; duration = newDuration;
controller = StatusController( controller = StatusController(
@ -75,7 +70,6 @@ class _MemorySlideState extends State<MemorySlide>
final timeline = context.read<TimelineModel>(); final timeline = context.read<TimelineModel>();
if (controller!.done) { if (controller!.done) {
timelineOverlay.reset();
timeline.nextMemory(); timeline.nextMemory();
} }
}, ['done']); }, ['done']);
@ -85,38 +79,36 @@ class _MemorySlideState extends State<MemorySlide>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<TimelineOverlayModel>( return Consumer<TimelineModel>(
builder: (_, timelineOverlay, __) => Consumer<TimelineModel>( builder: (___, timeline, ____) => Status(
builder: (___, timeline, ____) => Status( controller: controller,
controller: controller, paused: timeline.paused,
paused: timeline.paused, hideProgressBar: !timeline.showOverlay,
hideProgressBar: !timelineOverlay.showOverlay, child: MemoryView(
child: MemoryView( memory: widget.memory,
memory: widget.memory, loopVideo: false,
loopVideo: false, onFileDownloaded: () {
onFileDownloaded: () { if (widget.memory.type == MemoryType.photo) {
if (widget.memory.type == MemoryType.photo) { initializeAnimation(DEFAULT_IMAGE_DURATION);
initializeAnimation(DEFAULT_IMAGE_DURATION); }
} },
}, onVideoControllerInitialized: (controller) {
onVideoControllerInitialized: (controller) { if (mounted) {
if (mounted) { initializeAnimation(controller.value.duration);
initializeAnimation(controller.value.duration);
timeline.addListener(() { timeline.addListener(() {
if (!mounted) { if (!mounted) {
return; return;
} }
if (timeline.paused) { if (timeline.paused) {
controller.pause(); controller.pause();
} else { } else {
controller.play(); controller.play();
} }
}, ['paused']); }, ['paused']);
} }
}, },
),
), ),
), ),
); );

View File

@ -3,7 +3,6 @@ import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:share_location/constants/spacing.dart'; import 'package:share_location/constants/spacing.dart';
import 'package:share_location/models/timeline.dart'; import 'package:share_location/models/timeline.dart';
import 'package:share_location/models/timeline_overlay.dart';
class TimelineOverlay extends StatelessWidget { class TimelineOverlay extends StatelessWidget {
final DateTime date; final DateTime date;
@ -21,7 +20,6 @@ class TimelineOverlay extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final timeline = context.watch<TimelineModel>(); final timeline = context.watch<TimelineModel>();
final overlayController = context.watch<TimelineOverlayModel>();
return Stack( return Stack(
children: <Widget>[ children: <Widget>[
@ -34,7 +32,7 @@ class TimelineOverlay extends StatelessWidget {
child: AnimatedOpacity( child: AnimatedOpacity(
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 500),
curve: Curves.linearToEaseOut, curve: Curves.linearToEaseOut,
opacity: overlayController.showOverlay ? 1.0 : 0.0, opacity: timeline.showOverlay ? 1.0 : 0.0,
child: Text( child: Text(
DateFormat('dd. MMMM yyyy').format(date), DateFormat('dd. MMMM yyyy').format(date),
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -50,7 +48,7 @@ class TimelineOverlay extends StatelessWidget {
child: AnimatedOpacity( child: AnimatedOpacity(
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 500),
curve: Curves.linearToEaseOut, curve: Curves.linearToEaseOut,
opacity: overlayController.showOverlay ? 1.0 : 0.0, opacity: timeline.showOverlay ? 1.0 : 0.0,
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
AnimatedOpacity( AnimatedOpacity(

View File

@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:share_location/foreign_types/memory.dart'; import 'package:share_location/foreign_types/memory.dart';
import 'package:share_location/models/timeline.dart'; import 'package:share_location/models/timeline.dart';
import 'package:share_location/models/timeline_overlay.dart';
import 'package:share_location/widgets/memory_sheet.dart'; import 'package:share_location/widgets/memory_sheet.dart';
import 'package:share_location/widgets/memory_slide.dart'; import 'package:share_location/widgets/memory_slide.dart';
import 'package:share_location/widgets/timeline_overlay.dart'; import 'package:share_location/widgets/timeline_overlay.dart';
@ -24,74 +23,38 @@ class TimelinePage extends StatefulWidget {
} }
class _TimelinePageState extends State<TimelinePage> { class _TimelinePageState extends State<TimelinePage> {
final timelineOverlayController = TimelineOverlayModel();
final pageController = PageController(); final pageController = PageController();
Timer? overlayRemover; Timer? overlayRemover;
void _handleOverlayChangeBasedOnMemoryPack() {
if (!mounted) {
return;
}
final timeline = context.read<TimelineModel>();
if (timeline.paused) {
timelineOverlayController.hideOverlay();
} else {
timelineOverlayController.restoreOverlay();
}
}
void _jumpToCorrectPage() {
if (!mounted) {
return;
}
final timeline = context.read<TimelineModel>();
if (timeline.memoryIndex != pageController.page) {
pageController.animateToPage(
timeline.memoryIndex,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOutQuad,
);
}
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final timeline = context.read<TimelineModel>(); final timeline = context.read<TimelineModel>();
timelineOverlayController.addListener(() { // Jump to correct page
timeline.addListener(() {
if (!mounted) { if (!mounted) {
return; return;
} }
// Force update to ensure overlays are up-to-date. final timeline = context.read<TimelineModel>();
setState(() {});
}, ['showOverlay']);
timelineOverlayController if (timeline.memoryIndex != pageController.page) {
.addListener(_handleOverlayChangeBasedOnMemoryPack, ['state']); pageController.animateToPage(
timeline.memoryIndex,
timeline.addListener(_jumpToCorrectPage, ['memoryIndex']); duration: const Duration(milliseconds: 300),
curve: Curves.easeOutQuad,
);
}
}, ['memoryIndex']);
} }
@override @override
void dispose() { void dispose() {
pageController.dispose(); pageController.dispose();
try {
final timeline = context.read<TimelineModel>();
timeline.removeListener(_jumpToCorrectPage);
} catch (error) {
// Timeline has been removed completely
}
super.dispose(); super.dispose();
} }
@ -119,24 +82,9 @@ class _TimelinePageState extends State<TimelinePage> {
timeline.resume(); timeline.resume();
}, },
onTapDown: (_) { onTapDown: (_) => timeline.pause(),
timeline.pause(); onTapUp: (_) => timeline.resume(),
onTapCancel: () => timeline.resume(),
overlayRemover = Timer(
const Duration(milliseconds: 600),
timelineOverlayController.hideOverlay,
);
},
onTapUp: (_) {
overlayRemover?.cancel();
timeline.resume();
timelineOverlayController.restoreOverlay();
},
onTapCancel: () {
overlayRemover?.cancel();
timeline.resume();
timelineOverlayController.restoreOverlay();
},
onHorizontalDragEnd: (details) { onHorizontalDragEnd: (details) {
if (details.primaryVelocity! < 0) { if (details.primaryVelocity! < 0) {
timeline.nextMemory(); timeline.nextMemory();
@ -144,28 +92,25 @@ class _TimelinePageState extends State<TimelinePage> {
timeline.previousMemory(); timeline.previousMemory();
} }
}, },
child: ChangeNotifierProvider.value( child: Stack(
value: timelineOverlayController, fit: StackFit.expand,
child: Stack( children: <Widget>[
fit: StackFit.expand, PageView.builder(
children: <Widget>[ controller: pageController,
PageView.builder( physics: const NeverScrollableScrollPhysics(),
controller: pageController, scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(), itemBuilder: (_, index) => MemorySlide(
scrollDirection: Axis.horizontal, key: Key(widget.memories[index].filename),
itemBuilder: (_, index) => MemorySlide( memory: widget.memories[index],
key: Key(widget.memories[index].filename),
memory: widget.memories[index],
),
itemCount: widget.memories.length,
), ),
TimelineOverlay( itemCount: widget.memories.length,
date: widget.date, ),
memoriesAmount: widget.memories.length, TimelineOverlay(
memoryIndex: timeline.memoryIndex + 1, date: widget.date,
), memoriesAmount: widget.memories.length,
], memoryIndex: timeline.memoryIndex + 1,
), ),
],
), ),
); );
} }