blob: 59b694e7c7bd72e497411ae0bb5293df23db87a7 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'package:fidl/fidl.dart' show InterfaceHandle;
import 'package:fidl_fuchsia_mem/fidl.dart' show Buffer;
import 'package:fidl_fuchsia_skia_skottie/fidl.dart' as skottie;
import 'package:fidl_fuchsia_sys/fidl.dart';
import 'package:fidl_fuchsia_ui_app/fidl.dart' show ViewProviderProxy;
import 'package:fidl_fuchsia_ui_views/fidl_async.dart'
show ViewToken, ViewHolderToken;
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:fuchsia_scenic_flutter/child_view.dart' show ChildView;
import 'package:fuchsia_scenic_flutter/child_view_connection.dart'
show ChildViewConnection;
import 'package:lib.app.dart/app.dart';
import 'package:meta/meta.dart';
import 'package:zircon/zircon.dart';
typedef LoadCallback = void Function(
skottie.Status status, skottie.Player player);
/// A [Widget] that displays lottie animation in a scenic view.
class LottiePlayer extends StatefulWidget {
/// The JSON data of the animation as a string.
final String json;
/// The background color.
final Color backgroundColor;
/// Called after animation is loaded.
final LoadCallback onLoad;
/// Loops the animation. Default [true].
final bool loop;
/// Starts playing the animation after loading. Default [true].
final bool autoplay;
/// Constructor.
const LottiePlayer({
@required this.json,
this.backgroundColor = Colors.black,
this.loop = true,
this.autoplay = true,
Key key,
this.onLoad,
}) : super(key: key);
@override
_LottiePlayerState createState() => _LottiePlayerState();
}
class _LottiePlayerState extends State<LottiePlayer> {
final ComponentControllerProxy _controller = ComponentControllerProxy();
final skottie.LoaderProxy _loader = skottie.LoaderProxy();
ChildViewConnection _connection;
@override
void initState() {
super.initState();
_launchViewer();
_loadViewer();
}
@override
void didUpdateWidget(LottiePlayer old) {
super.didUpdateWidget(old);
if (old.json == widget.json &&
old.backgroundColor == widget.backgroundColor &&
old.loop == widget.loop &&
old.autoplay == widget.autoplay) {
return;
}
_loadViewer();
}
@override
void dispose() {
_loader?.ctrl?.close();
_controller?.ctrl?.close();
_connection = null;
super.dispose();
}
@override
Widget build(BuildContext context) => ChildView(
connection: _connection,
hitTestable: false,
focusable: false,
);
void _launchViewer() {
final startupContext = StartupContext.fromStartupInfo();
final incomingServices = Services();
final launcher = LauncherProxy();
connectToService(startupContext.environmentServices, launcher.ctrl);
launcher.createComponent(
LaunchInfo(
url: 'skottie_viewer',
directoryRequest: incomingServices.request(),
),
_controller.ctrl.request(),
);
launcher.ctrl.close();
final viewTokens = EventPairPair();
assert(viewTokens.status == ZX.OK);
final viewHolderToken = ViewHolderToken(value: viewTokens.first);
final viewToken = ViewToken(value: viewTokens.second);
final viewProvider = ViewProviderProxy();
incomingServices.connectToService(viewProvider.ctrl);
viewProvider.createView(viewToken.value, null, null);
viewProvider.ctrl.close();
incomingServices
..connectToService(_loader.ctrl)
..close();
_connection = ChildViewConnection(viewHolderToken);
}
void _loadViewer() {
final SizedVmo vmo =
SizedVmo.fromUint8List(Uint8List.fromList(widget.json.codeUnits));
final options = skottie.Options(
backgroundColor: widget.backgroundColor.value,
loop: widget.loop,
autoplay: widget.autoplay,
);
_loader.load(Buffer(vmo: vmo, size: vmo.size), options,
(skottie.Status status, InterfaceHandle<skottie.Player> player) {
widget.onLoad(status, skottie.PlayerProxy()..ctrl.bind(player));
});
}
}