This commit is contained in:
Thibault Deckers 2023-03-01 18:59:48 +01:00
parent 4fdaf23a0e
commit 7797c03170
15 changed files with 236 additions and 251 deletions

View file

@ -1,7 +1,4 @@
import 'package:aves/model/settings/enums/accessibility_animations.dart'; import 'package:flutter/foundation.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
class Durations { class Durations {
// Flutter animations (with margin) // Flutter animations (with margin)
@ -72,26 +69,6 @@ class Durations {
static const mapIdleDebounceDelay = Duration(milliseconds: 100); static const mapIdleDebounceDelay = Duration(milliseconds: 100);
} }
class DurationsProvider extends StatelessWidget {
final Widget child;
const DurationsProvider({
super.key,
required this.child,
});
@override
Widget build(BuildContext context) {
return ProxyProvider<Settings, DurationsData>(
update: (context, settings, __) {
final enabled = settings.accessibilityAnimations.animate;
return enabled ? DurationsData() : DurationsData.noAnimation();
},
child: child,
);
}
}
@immutable @immutable
class DurationsData { class DurationsData {
// common animations // common animations

View file

@ -33,6 +33,7 @@ import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/common/behaviour/route_tracker.dart'; import 'package:aves/widgets/common/behaviour/route_tracker.dart';
import 'package:aves/widgets/common/behaviour/routes.dart'; import 'package:aves/widgets/common/behaviour/routes.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/providers/durations_provider.dart';
import 'package:aves/widgets/common/providers/highlight_info_provider.dart'; import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
import 'package:aves/widgets/home_page.dart'; import 'package:aves/widgets/home_page.dart';
@ -190,18 +191,16 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
Widget build(BuildContext context) { Widget build(BuildContext context) {
// place the settings provider above `MaterialApp` // place the settings provider above `MaterialApp`
// so it can be used during navigation transitions // so it can be used during navigation transitions
return Provider<AppFlavor>.value( return MultiProvider(
value: widget.flavor, providers: [
child: ChangeNotifierProvider<Settings>.value( Provider<AppFlavor>.value(value: widget.flavor),
value: settings, ChangeNotifierProvider<Settings>.value(value: settings),
child: ListenableProvider<ValueNotifier<AppMode>>.value( ListenableProvider<ValueNotifier<AppMode>>.value(value: _appModeNotifier),
value: _appModeNotifier, Provider<CollectionSource>.value(value: _mediaStoreSource),
child: Provider<CollectionSource>.value( Provider<TvRailController>.value(value: _tvRailController),
value: _mediaStoreSource, DurationsProvider(),
child: Provider<TvRailController>.value( HighlightInfoProvider(),
value: _tvRailController, ],
child: DurationsProvider(
child: HighlightInfoProvider(
child: OverlaySupport( child: OverlaySupport(
child: FutureBuilder<void>( child: FutureBuilder<void>(
future: _appSetup, future: _appSetup,
@ -275,12 +274,6 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
}, },
), ),
), ),
),
),
),
),
),
),
); );
} }

View file

@ -19,7 +19,7 @@ import 'package:aves/widgets/collection/draggable_thumb_label.dart';
import 'package:aves/widgets/collection/grid/list_details_theme.dart'; import 'package:aves/widgets/collection/grid/list_details_theme.dart';
import 'package:aves/widgets/collection/grid/section_layout.dart'; import 'package:aves/widgets/collection/grid/section_layout.dart';
import 'package:aves/widgets/collection/grid/tile.dart'; import 'package:aves/widgets/collection/grid/tile.dart';
import 'package:aves/widgets/common/basic/draggable_scrollbar.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/scrollbar.dart';
import 'package:aves/widgets/common/basic/insets.dart'; import 'package:aves/widgets/common/basic/insets.dart';
import 'package:aves/widgets/common/behaviour/sloppy_scroll_physics.dart'; import 'package:aves/widgets/common/behaviour/sloppy_scroll_physics.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';

View file

@ -14,7 +14,7 @@ import 'package:aves/model/source/collection_source.dart';
import 'package:aves/services/intent_service.dart'; import 'package:aves/services/intent_service.dart';
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/collection/collection_grid.dart'; import 'package:aves/widgets/collection/collection_grid.dart';
import 'package:aves/widgets/common/basic/draggable_scrollbar.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/notifications.dart';
import 'package:aves/widgets/common/basic/insets.dart'; import 'package:aves/widgets/common/basic/insets.dart';
import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/common/behaviour/pop/double_back.dart'; import 'package:aves/widgets/common/behaviour/pop/double_back.dart';
@ -52,7 +52,7 @@ class CollectionPage extends StatefulWidget {
class _CollectionPageState extends State<CollectionPage> { class _CollectionPageState extends State<CollectionPage> {
final List<StreamSubscription> _subscriptions = []; final List<StreamSubscription> _subscriptions = [];
late CollectionLens _collection; late CollectionLens _collection;
final StreamController<DraggableScrollBarEvent> _draggableScrollBarEventStreamController = StreamController.broadcast(); final StreamController<DraggableScrollbarEvent> _draggableScrollBarEventStreamController = StreamController.broadcast();
final DoubleBackPopHandler _doubleBackPopHandler = DoubleBackPopHandler(); final DoubleBackPopHandler _doubleBackPopHandler = DoubleBackPopHandler();
@override @override
@ -146,7 +146,7 @@ class _CollectionPageState extends State<CollectionPage> {
final canNavigate = context.select<ValueNotifier<AppMode>, bool>((v) => v.value.canNavigate); final canNavigate = context.select<ValueNotifier<AppMode>, bool>((v) => v.value.canNavigate);
final showBottomNavigationBar = canNavigate && enableBottomNavigationBar; final showBottomNavigationBar = canNavigate && enableBottomNavigationBar;
return NotificationListener<DraggableScrollBarNotification>( return NotificationListener<DraggableScrollbarNotification>(
onNotification: (notification) { onNotification: (notification) {
_draggableScrollBarEventStreamController.add(notification.event); _draggableScrollBarEventStreamController.add(notification.event);
return false; return false;

View file

@ -0,0 +1,38 @@
import 'package:flutter/rendering.dart';
class ArrowClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
final path = Path();
path.lineTo(0.0, size.height);
path.lineTo(size.width, size.height);
path.lineTo(size.width, 0.0);
path.lineTo(0.0, 0.0);
path.close();
const arrowWidth = 8.0;
final startPointX = (size.width - arrowWidth) / 2;
var startPointY = size.height / 2 - arrowWidth / 2;
path.moveTo(startPointX, startPointY);
path.lineTo(startPointX + arrowWidth / 2, startPointY - arrowWidth / 2);
path.lineTo(startPointX + arrowWidth, startPointY);
path.lineTo(startPointX + arrowWidth, startPointY + 1.0);
path.lineTo(startPointX + arrowWidth / 2, startPointY - arrowWidth / 2 + 1.0);
path.lineTo(startPointX, startPointY + 1.0);
path.close();
startPointY = size.height / 2 + arrowWidth / 2;
path.moveTo(startPointX + arrowWidth, startPointY);
path.lineTo(startPointX + arrowWidth / 2, startPointY + arrowWidth / 2);
path.lineTo(startPointX, startPointY);
path.lineTo(startPointX, startPointY - 1.0);
path.lineTo(startPointX + arrowWidth / 2, startPointY + arrowWidth / 2 - 1.0);
path.lineTo(startPointX + arrowWidth, startPointY - 1.0);
path.close();
return path;
}
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}

View file

@ -0,0 +1,10 @@
import 'package:flutter/widgets.dart';
@immutable
class DraggableScrollbarNotification extends Notification {
final DraggableScrollbarEvent event;
const DraggableScrollbarNotification(this.event);
}
enum DraggableScrollbarEvent { dragStart, dragEnd }

View file

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
class ScrollLabel extends StatelessWidget {
final Animation<double> animation;
final Color backgroundColor;
final Widget child;
const ScrollLabel({
super.key,
required this.child,
required this.animation,
required this.backgroundColor,
});
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: animation,
child: Container(
margin: const EdgeInsetsDirectional.only(end: 12.0),
child: Material(
elevation: 4.0,
color: backgroundColor,
borderRadius: const BorderRadius.all(Radius.circular(16)),
child: child,
),
),
);
}
}

View file

@ -1,7 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/notifications.dart';
import 'package:flutter/material.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/scroll_label.dart';
import 'package:aves/widgets/common/basic/draggable_scrollbar/transition.dart';
import 'package:flutter/widgets.dart';
/* /*
adapted from package `draggable_scrollbar` v0.0.4: adapted from package `draggable_scrollbar` v0.0.4:
@ -109,35 +111,6 @@ class DraggableScrollbar extends StatefulWidget {
} }
} }
class ScrollLabel extends StatelessWidget {
final Animation<double> animation;
final Color backgroundColor;
final Widget child;
const ScrollLabel({
super.key,
required this.child,
required this.animation,
required this.backgroundColor,
});
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: animation,
child: Container(
margin: const EdgeInsetsDirectional.only(end: 12.0),
child: Material(
elevation: 4.0,
color: backgroundColor,
borderRadius: const BorderRadius.all(Radius.circular(16)),
child: child,
),
),
);
}
}
class _DraggableScrollbarState extends State<DraggableScrollbar> with TickerProviderStateMixin { class _DraggableScrollbarState extends State<DraggableScrollbar> with TickerProviderStateMixin {
final ValueNotifier<double> _thumbOffsetNotifier = ValueNotifier(0), _viewOffsetNotifier = ValueNotifier(0); final ValueNotifier<double> _thumbOffsetNotifier = ValueNotifier(0), _viewOffsetNotifier = ValueNotifier(0);
bool _isDragInProcess = false; bool _isDragInProcess = false;
@ -304,7 +277,7 @@ class _DraggableScrollbarState extends State<DraggableScrollbar> with TickerProv
} }
void _onVerticalDragStart() { void _onVerticalDragStart() {
const DraggableScrollBarNotification(DraggableScrollBarEvent.dragStart).dispatch(context); const DraggableScrollbarNotification(DraggableScrollbarEvent.dragStart).dispatch(context);
_labelAnimationController.forward(); _labelAnimationController.forward();
_fadeoutTimer?.cancel(); _fadeoutTimer?.cancel();
_showThumb(); _showThumb();
@ -326,7 +299,7 @@ class _DraggableScrollbarState extends State<DraggableScrollbar> with TickerProv
} }
void _onVerticalDragEnd() { void _onVerticalDragEnd() {
const DraggableScrollBarNotification(DraggableScrollBarEvent.dragEnd).dispatch(context); const DraggableScrollbarNotification(DraggableScrollbarEvent.dragEnd).dispatch(context);
_scheduleFadeout(); _scheduleFadeout();
setState(() => _isDragInProcess = false); setState(() => _isDragInProcess = false);
} }
@ -373,79 +346,3 @@ class _DraggableScrollbarState extends State<DraggableScrollbar> with TickerProv
} }
} }
} }
///This cut 2 lines in arrow shape
class ArrowClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
final path = Path();
path.lineTo(0.0, size.height);
path.lineTo(size.width, size.height);
path.lineTo(size.width, 0.0);
path.lineTo(0.0, 0.0);
path.close();
const arrowWidth = 8.0;
final startPointX = (size.width - arrowWidth) / 2;
var startPointY = size.height / 2 - arrowWidth / 2;
path.moveTo(startPointX, startPointY);
path.lineTo(startPointX + arrowWidth / 2, startPointY - arrowWidth / 2);
path.lineTo(startPointX + arrowWidth, startPointY);
path.lineTo(startPointX + arrowWidth, startPointY + 1.0);
path.lineTo(startPointX + arrowWidth / 2, startPointY - arrowWidth / 2 + 1.0);
path.lineTo(startPointX, startPointY + 1.0);
path.close();
startPointY = size.height / 2 + arrowWidth / 2;
path.moveTo(startPointX + arrowWidth, startPointY);
path.lineTo(startPointX + arrowWidth / 2, startPointY + arrowWidth / 2);
path.lineTo(startPointX, startPointY);
path.lineTo(startPointX, startPointY - 1.0);
path.lineTo(startPointX + arrowWidth / 2, startPointY + arrowWidth / 2 - 1.0);
path.lineTo(startPointX + arrowWidth, startPointY - 1.0);
path.close();
return path;
}
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
class SlideFadeTransition extends StatelessWidget {
final Animation<double> animation;
final Widget child;
const SlideFadeTransition({
super.key,
required this.animation,
required this.child,
});
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (context, child) => animation.value == 0.0 ? Container() : child!,
child: SlideTransition(
position: Tween(
begin: Offset((context.isRtl ? -1 : 1) * .3, 0),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: child,
),
),
);
}
}
@immutable
class DraggableScrollBarNotification extends Notification {
final DraggableScrollBarEvent event;
const DraggableScrollBarNotification(this.event);
}
enum DraggableScrollBarEvent { dragStart, dragEnd }

View file

@ -0,0 +1,31 @@
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:flutter/widgets.dart';
class SlideFadeTransition extends StatelessWidget {
final Animation<double> animation;
final Widget child;
const SlideFadeTransition({
super.key,
required this.animation,
required this.child,
});
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (context, child) => animation.value == 0.0 ? Container() : child!,
child: SlideTransition(
position: Tween(
begin: Offset((context.isRtl ? -1 : 1) * .3, 0),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: child,
),
),
);
}
}

View file

@ -1,4 +1,5 @@
import 'package:aves/widgets/common/basic/draggable_scrollbar.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/arrow_clipper.dart';
import 'package:aves/widgets/common/basic/draggable_scrollbar/scrollbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
const double avesScrollThumbHeight = 48; const double avesScrollThumbHeight = 48;

View file

@ -0,0 +1,16 @@
import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/durations.dart';
import 'package:provider/provider.dart';
class DurationsProvider extends ProxyProvider<Settings, DurationsData> {
DurationsProvider({
super.key,
super.child,
}) : super(
update: (context, settings, __) {
final enabled = settings.accessibilityAnimations.animate;
return enabled ? DurationsData() : DurationsData.noAnimation();
},
);
}

View file

@ -1,20 +1,11 @@
import 'package:aves/model/highlight.dart'; import 'package:aves/model/highlight.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class HighlightInfoProvider extends StatelessWidget { class HighlightInfoProvider extends ChangeNotifierProvider<HighlightInfo> {
final Widget child; HighlightInfoProvider({
const HighlightInfoProvider({
super.key, super.key,
required this.child, super.child,
}); }) : super(
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<HighlightInfo>(
create: (context) => HighlightInfo(), create: (context) => HighlightInfo(),
child: child,
); );
} }
}

View file

@ -12,7 +12,8 @@ import 'package:aves/model/source/enums/enums.dart';
import 'package:aves/model/vaults/vaults.dart'; import 'package:aves/model/vaults/vaults.dart';
import 'package:aves/theme/colors.dart'; import 'package:aves/theme/colors.dart';
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/common/basic/draggable_scrollbar.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/scrollbar.dart';
import 'package:aves/widgets/common/basic/draggable_scrollbar/notifications.dart';
import 'package:aves/widgets/common/basic/insets.dart'; import 'package:aves/widgets/common/basic/insets.dart';
import 'package:aves/widgets/common/basic/scaffold.dart'; import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/common/behaviour/pop/double_back.dart'; import 'package:aves/widgets/common/behaviour/pop/double_back.dart';
@ -61,7 +62,7 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
final QueryTest<T> applyQuery; final QueryTest<T> applyQuery;
final Widget Function() emptyBuilder; final Widget Function() emptyBuilder;
final HeroType heroType; final HeroType heroType;
final StreamController<DraggableScrollBarEvent> _draggableScrollBarEventStreamController = StreamController.broadcast(); final StreamController<DraggableScrollbarEvent> _draggableScrollBarEventStreamController = StreamController.broadcast();
FilterGridPage({ FilterGridPage({
super.key, super.key,
@ -145,7 +146,7 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
final canNavigate = context.select<ValueNotifier<AppMode>, bool>((v) => v.value.canNavigate); final canNavigate = context.select<ValueNotifier<AppMode>, bool>((v) => v.value.canNavigate);
final showBottomNavigationBar = canNavigate && enableBottomNavigationBar; final showBottomNavigationBar = canNavigate && enableBottomNavigationBar;
return NotificationListener<DraggableScrollBarNotification>( return NotificationListener<DraggableScrollbarNotification>(
onNotification: (notification) { onNotification: (notification) {
_draggableScrollBarEventStreamController.add(notification.event); _draggableScrollBarEventStreamController.add(notification.event);
return false; return false;

View file

@ -1,12 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:aves/widgets/common/basic/draggable_scrollbar.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/notifications.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class FloatingNavBar extends StatefulWidget { class FloatingNavBar extends StatefulWidget {
final ScrollController? scrollController; final ScrollController? scrollController;
final Stream<DraggableScrollBarEvent> events; final Stream<DraggableScrollbarEvent> events;
final double childHeight; final double childHeight;
final Widget child; final Widget child;
@ -109,12 +109,12 @@ class _FloatingNavBarState extends State<FloatingNavBar> with SingleTickerProvid
} }
} }
void _onDraggableScrollBarEvent(DraggableScrollBarEvent event) { void _onDraggableScrollBarEvent(DraggableScrollbarEvent event) {
switch (event) { switch (event) {
case DraggableScrollBarEvent.dragStart: case DraggableScrollbarEvent.dragStart:
_isDragging = true; _isDragging = true;
break; break;
case DraggableScrollBarEvent.dragEnd: case DraggableScrollbarEvent.dragEnd:
_isDragging = false; _isDragging = false;
break; break;
} }

View file

@ -5,7 +5,7 @@ import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
import 'package:aves/widgets/collection/collection_page.dart'; import 'package:aves/widgets/collection/collection_page.dart';
import 'package:aves/widgets/common/basic/draggable_scrollbar.dart'; import 'package:aves/widgets/common/basic/draggable_scrollbar/notifications.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/extensions/media_query.dart'; import 'package:aves/widgets/common/extensions/media_query.dart';
import 'package:aves/widgets/common/identity/aves_app_bar.dart'; import 'package:aves/widgets/common/identity/aves_app_bar.dart';
@ -17,7 +17,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class AppBottomNavBar extends StatefulWidget { class AppBottomNavBar extends StatefulWidget {
final Stream<DraggableScrollBarEvent> events; final Stream<DraggableScrollbarEvent> events;
// collection loaded in the `CollectionPage`, if any // collection loaded in the `CollectionPage`, if any
final CollectionLens? currentCollection; final CollectionLens? currentCollection;