Skip to content

Instantly share code, notes, and snippets.

@luigi-rosso
Created September 13, 2019 19:12
Show Gist options
  • Save luigi-rosso/d6635c899baf4e7b94e5766859f03b19 to your computer and use it in GitHub Desktop.
Save luigi-rosso/d6635c899baf4e7b94e5766859f03b19 to your computer and use it in GitHub Desktop.
import 'dart:math';
import 'package:flare_dart/math/mat2d.dart';
import 'package:flare_flutter/flare.dart';
import 'package:flare_flutter/flare_controller.dart';
import 'package:flutter/animation.dart';
enum CameraButtonState { closed, camera, accept, upload, cancel }
const double _mixIconTime = 0.4;
const double _interpolateProgressTime = 0.1;
class CameraButtonController extends FlareController {
ActorAnimation _open;
ActorAnimation _progress;
ActorAnimation _showProgress;
ActorAnimation _showIcons;
ActorAnimation _showCancel;
ActorAnimation _iconEmpty;
ActorAnimation _iconAccept;
ActorAnimation _iconCamera;
ActorAnimation _iconAnimation;
double _openTime = 0.0;
double _iconMix = 0.0;
double _showProgressTime = 0.0;
double _showCancelTime = 0.0;
double _showIconsTime = 0.0;
CameraButtonState _state;
CameraButtonState get state => _state;
set state(CameraButtonState value) {
if (value == _state) {
return;
}
_state = value;
// reset icon mix
_iconMix = 0;
switch (_state) {
case CameraButtonState.camera:
_iconAnimation = _iconCamera;
break;
case CameraButtonState.accept:
_iconAnimation = _iconAccept;
break;
case CameraButtonState.cancel:
case CameraButtonState.upload:
_iconAnimation = _iconEmpty;
break;
default:
_iconAnimation = null;
break;
}
isActive.value = true;
}
double _progressValue = 0.0;
double _targetProgress = 0.0;
double get progress => _targetProgress;
set progress(double value) {
isActive.value = true;
_targetProgress = value.clamp(0, 1);
}
@override
bool advance(FlutterActorArtboard artboard, double elapsed) {
double displayProgress = 0;
bool keepRunning = false;
switch (_state) {
case CameraButtonState.closed:
_openTime = max(0, _openTime - elapsed);
if (_openTime == 0) {
// reset progress visibility to 0 once fully closed.
_showProgressTime = 0;
_showCancelTime = 0;
_showIconsTime = 0;
}
if (_openTime > 0) {
keepRunning = true;
}
break;
case CameraButtonState.camera:
case CameraButtonState.accept:
_openTime = min(_open.duration, _openTime + elapsed);
_showProgressTime = max(0, _showProgressTime - elapsed);
_showIconsTime = min(_showIcons.duration, _showIconsTime + elapsed);
_showCancelTime = max(0, _showCancelTime - elapsed);
if (_openTime < _open.duration ||
_showProgressTime > 0 ||
_showIconsTime < _showIcons.duration ||
_showCancelTime > 0) {
keepRunning = true;
}
break;
case CameraButtonState.cancel:
displayProgress = _targetProgress;
_showIconsTime = min(_showIcons.duration, _showIconsTime + elapsed);
_showCancelTime = min(_showCancel.duration, _showCancelTime + elapsed);
_openTime = min(_open.duration, _openTime + elapsed);
_showProgressTime =
min(_showProgress.duration, _showProgressTime + elapsed);
if (_showIconsTime < _showIcons.duration ||
_showCancelTime < _showCancel.duration ||
_openTime < _open.duration ||
_showProgressTime < _showProgress.duration) {
keepRunning = true;
}
break;
case CameraButtonState.upload:
displayProgress = _targetProgress;
_openTime = min(_open.duration, _openTime + elapsed);
_showCancelTime = max(0, _showCancelTime - elapsed);
_showProgressTime =
min(_showProgress.duration, _showProgressTime + elapsed);
if (_openTime < _open.duration ||
_showCancelTime > 0 ||
_showProgressTime < _showProgress.duration) {
keepRunning = true;
}
break;
}
_progressValue += (displayProgress - _progressValue) *
min(1.0, elapsed / _interpolateProgressTime);
if ((_progressValue - displayProgress).abs() > 0.01) {
keepRunning = true;
}
// finally apply animations
_showIcons.apply(_showIconsTime, artboard, 1.0);
_showProgress.apply(_showProgressTime, artboard, 1.0);
_showCancel.apply(_showCancelTime, artboard, 1.0);
_open.apply(_openTime, artboard, 1.0);
// interpolate towards icon
if (_iconAnimation != null) {
_iconMix = min(1, _iconMix + (elapsed / _mixIconTime));
_iconAnimation.apply(0.0, artboard, Curves.easeInOut.transform(_iconMix));
if ((_iconMix - 1).abs() > 0.01) {
keepRunning = true;
}
}
_progress.apply(_progressValue * _progress.duration, artboard, 1.0);
return keepRunning;
}
@override
void initialize(FlutterActorArtboard artboard) {
_open = artboard.getAnimation("open");
_progress = artboard.getAnimation("progress");
_showProgress = artboard.getAnimation("show-progress");
_showCancel = artboard.getAnimation("show-cancel");
_showIcons = artboard.getAnimation("show-icons");
_iconEmpty = artboard.getAnimation("icon-none");
_iconAccept = artboard.getAnimation("icon-check");
_iconCamera = artboard.getAnimation("icon-camera");
state = CameraButtonState.closed;
}
@override
void setViewTransform(Mat2D viewTransform) {
// intentionally empty, we don't need the view transform.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment