This commit is contained in:
Christien Rioux 2023-07-26 22:38:09 -04:00
parent 9fa1666e8b
commit f754f7d5ed
27 changed files with 655 additions and 289 deletions

98
lib/tools/animations.dart Normal file
View file

@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
enum AnimationTrigger {
onPageLoad,
onActionTrigger,
}
class AnimationInfo {
AnimationInfo({
required this.trigger,
required this.effects,
this.loop = false,
this.reverse = false,
this.applyInitialState = true,
});
final AnimationTrigger trigger;
final List<Effect<dynamic>> effects;
final bool applyInitialState;
final bool loop;
final bool reverse;
late Adapter adapter;
late AnimationController controller;
}
void createAnimation(AnimationInfo animation, TickerProvider vsync) {
final newController = AnimationController(vsync: vsync);
animation
..controller = newController
..adapter = (ValueAdapter(0)..attach(newController));
}
void setupAnimations(Iterable<AnimationInfo> animations, TickerProvider vsync) {
for (final animation in animations) {
createAnimation(animation, vsync);
}
}
extension AnimatedWidgetExtension on Widget {
Widget animateOnPageLoad(AnimationInfo animationInfo) => Animate(
controller:
animationInfo.applyInitialState ? null : animationInfo.controller,
adapter: animationInfo.applyInitialState ? null : animationInfo.adapter,
effects: animationInfo.effects,
child: this,
onPlay: (controller) => animationInfo.loop
? controller.repeat(reverse: animationInfo.reverse)
: null,
onComplete: (controller) => !animationInfo.loop && animationInfo.reverse
? controller.reverse()
: null);
Widget animateOnActionTrigger(
AnimationInfo animationInfo, {
bool hasBeenTriggered = false,
}) =>
hasBeenTriggered || animationInfo.applyInitialState
? Animate(
controller: animationInfo.controller,
adapter: animationInfo.adapter,
effects: animationInfo.effects,
child: this)
: this;
}
class TiltEffect extends Effect<Offset> {
const TiltEffect({
super.delay,
super.duration,
super.curve,
Offset? begin,
Offset? end,
}) : super(
begin: begin ?? Offset.zero,
end: end ?? Offset.zero,
);
@override
Widget build(
BuildContext context,
Widget child,
AnimationController controller,
EffectEntry entry,
) {
final animation = buildAnimation(controller, entry);
return getOptimizedBuilder<Offset>(
animation: animation,
builder: (_, __) => Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(animation.value.dx)
..rotateY(animation.value.dy),
alignment: Alignment.center,
child: child,
),
);
}
}

32
lib/tools/responsive.dart Normal file
View file

@ -0,0 +1,32 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
bool get isAndroid => !kIsWeb && Platform.isAndroid;
bool get isiOS => !kIsWeb && Platform.isIOS;
bool get isWeb => kIsWeb;
const kMobileWidthCutoff = 479.0;
bool isMobileWidth(BuildContext context) =>
MediaQuery.of(context).size.width < kMobileWidthCutoff;
bool responsiveVisibility({
required BuildContext context,
bool phone = true,
bool tablet = true,
bool tabletLandscape = true,
bool desktop = true,
}) {
final width = MediaQuery.of(context).size.width;
if (width < kMobileWidthCutoff) {
return phone;
} else if (width < 767) {
return tablet;
} else if (width < 991) {
return tabletLandscape;
} else {
return desktop;
}
}

View file

@ -1,6 +1,8 @@
export 'animations.dart';
export 'desktop_control.dart';
export 'external_stream_state.dart';
export 'json_tools.dart';
export 'phono_byte.dart';
export 'protobuf_tools.dart';
export 'responsive.dart';
export 'widget_helpers.dart';