blob: cbbb17f05a26c49f6f59b847c3188fd87ccacb26 [file] [log] [blame]
// Copyright 2015 The Vanadium 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 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import '../models/all.dart' as model;
import '../stores/store.dart';
import '../styles/common.dart' as style;
import '../utils/keyvalue.dart';
import 'slideshow.dart';
// SlideListPage is the full page view of the list of slides for a deck.
class SlideListPage extends StatelessComponent {
final String deckId;
final String title;
Store _store = new Store.singleton();
SlideListPage(this.deckId, this.title);
Widget build(BuildContext context) {
return new Scaffold(
toolBar: new ToolBar(
left: new IconButton(
icon: 'navigation/arrow_back',
onPressed: () => Navigator.of(context).pop()),
center: new Text(title)),
floatingActionButton: _buildPresentFab(context),
body: new Material(child: new SlideList(deckId)));
}
_buildPresentFab(BuildContext context) {
return new FloatingActionButton(
child: new Icon(icon: 'navigation/arrow_forward'), onPressed: () async {
model.PresentationAdvertisement presentation =
await _store.startPresentation(deckId);
Navigator
.of(context)
.push(new PageRoute(builder: (context) => new SlideshowPage(deckId)));
});
}
}
// SlideList is scrollable list view of slides for a deck.
class SlideList extends StatefulComponent {
final String deckId;
SlideList(this.deckId);
_SlideListState createState() => new _SlideListState();
}
class _SlideListState extends State<SlideList> {
Store _store = new Store.singleton();
List<model.Slide> _slides = new List<model.Slide>();
void updateSlides(List<model.Slide> slides) {
setState(() {
_slides = slides;
});
}
@override
void initState() {
super.initState();
_store.getAllSlides(config.deckId).then(updateSlides);
// TODO(aghassemi): Gracefully handle when deck is deleted while in this view.
}
Widget build(BuildContext context) {
// Create a list of <SlideNumber, Slide> pairs.
List<KeyValue<int, model.Slide>> slidesWithPosition = [];
for (var i = 0; i < _slides.length; i++) {
slidesWithPosition.add(new KeyValue(i, _slides[i]));
}
return new ScrollableList(
itemExtent: style.Size.listHeight,
items: slidesWithPosition,
itemBuilder: (context, kv) =>
_buildSlide(context, kv.key.toString(), kv.value, onTap: () {
_store.setCurrSlideNum(config.deckId, kv.key);
Navigator.of(context).push(new PageRoute(
builder: (context) => new SlideshowPage(config.deckId)));
}));
}
}
// TODO(aghassemi): Is this approach okay? Check with Flutter team.
// Builder gets called a lot by the ScrollableList and building RawImage
// is expensive so we cache.
// Expando is a weak map so this does not effect GC.
Expando<Widget> _weakSlideCache = new Expando<Widget>();
Widget _buildSlide(BuildContext context, String key, model.Slide slideData,
{Function onTap}) {
var cachedWidget = _weakSlideCache[slideData];
if (cachedWidget != null) {
return cachedWidget;
}
var thumbnail = new RawImage(
height: style.Size.listHeight,
bytes: new Uint8List.fromList(slideData.image),
fit: ImageFit.cover);
thumbnail = new Flexible(child: thumbnail);
var title = new Text('Slide $key', style: style.Text.subtitleStyle);
var notes = new Text(
'This is the teaser slide. It should be memorable and descriptive');
var titleAndNotes = new Flexible(
child: new Container(
child: new Column([title, notes], alignItems: FlexAlignItems.start),
padding: style.Spacing.normalPadding));
var card = new Container(
child: new Card(child: new Row([thumbnail, titleAndNotes])),
margin: style.Spacing.listItemMargin);
var listItem = new InkWell(key: new Key(key), child: card, onTap: onTap);
_weakSlideCache[slideData] = listItem;
return listItem;
}