blob: 6cfbd68965d23a6354cd68a30ff816f18a1dc4bc [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';
// SlideListPage is the full page view of the list of slides for a deck.
class SlideListPage extends StatelessComponent {
String _deckId;
String _title;
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)),
body: new Material(child: new SlideList(_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> {
_SlideListState();
Store _store = new Store.singleton();
List<model.Slide> _slides = new List<model.Slide>();
void updateSlides(List<model.Slide> slides) {
setState(() {
_slides = slides;
});
}
void initState() {
super.initState();
_store.getAllSlides(config.deckId).then(updateSlides);
}
Widget build(BuildContext context) {
// Create a list of <SlideNumber, Slide> pairs.
List<KeyValue<String, model.Slide>> slidesWithPosition = [];
for (var i = 0; i < _slides.length; i++) {
slidesWithPosition.add(new KeyValue(i.toString(), _slides[i]));
}
return new ScrollableList(
itemExtent: style.Size.listHeight,
items: slidesWithPosition,
itemBuilder: (context, kv) => _buildSlide(context, kv.key, kv.value));
}
}
// 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) {
var cachedWidget = weakSlideCache[slideData];
if (cachedWidget != null) {
return cachedWidget;
}
var thumbnail;
if (slideData.image != null) {
thumbnail = new RawImage(
height: style.Size.listHeight,
bytes: new Uint8List.fromList(slideData.image),
fit: ImageFit.cover);
} else {
// TODO(aghassemi): Replace with a proper default thumbnail.
thumbnail = new Text('No Slide Image');
}
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);
weakSlideCache[slideData] = listItem;
return listItem;
}