main.dart 19.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// Copyright 2015 The Chromium 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/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;

void main() {
  runApp(
    new ComplexLayoutApp()
  );
}

class ComplexLayoutApp extends StatefulWidget {
  @override
  ComplexLayoutAppState createState() => new ComplexLayoutAppState();

  static ComplexLayoutAppState of(BuildContext context) => context.ancestorStateOfType(const TypeMatcher<ComplexLayoutAppState>());
}

class ComplexLayoutAppState extends State<ComplexLayoutApp> {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      theme: lightTheme ? new ThemeData.light() : new ThemeData.dark(),
      title: 'Advanced Layout',
27
      home: new ComplexLayout()
28 29 30 31 32
    );
  }

  bool _lightTheme = true;
  bool get lightTheme => _lightTheme;
33
  set lightTheme(bool value) {
34 35 36 37
    setState(() {
      _lightTheme = value;
    });
  }
38 39 40 41 42 43

  void toggleAnimationSpeed() {
    setState(() {
      timeDilation = (timeDilation != 1.0) ? 1.0 : 5.0;
    });
  }
44 45 46 47 48 49 50 51 52 53 54 55
}

class ComplexLayout extends StatefulWidget {
  ComplexLayout({ Key key }) : super(key: key);

  @override
  ComplexLayoutState createState() => new ComplexLayoutState();

  static ComplexLayoutState of(BuildContext context) => context.ancestorStateOfType(const TypeMatcher<ComplexLayoutState>());

}

56 57 58 59
class FancyItemDelegate extends LazyBlockDelegate {
  @override
  Widget buildItem(BuildContext context, int index) {
    if (index % 2 == 0)
60
      return new FancyImageItem(index, key: new Key('Item $index'));
61
    else
62
      return new FancyGalleryItem(index, key: new Key('Item $index'));
63 64 65 66
  }

  @override
  bool shouldRebuild(FancyItemDelegate oldDelegate) => false;
67 68 69 70 71

  @override
  double estimateTotalExtent(int firstIndex, int lastIndex, double minOffset, double firstStartOffset, double lastEndOffset) {
    return double.INFINITY;
  }
72 73
}

74 75 76 77 78 79 80 81 82
class ComplexLayoutState extends State<ComplexLayout> {
  @override
  Widget build(BuildContext context) {

    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Advanced Layout'),
        actions: <Widget>[
          new IconButton(
Ian Hickson's avatar
Ian Hickson committed
83
            icon: new Icon(Icons.create),
84 85
            tooltip: 'Search',
            onPressed: () {
86
              print('Pressed search');
87 88 89 90 91 92 93 94
            }
          ),
          new TopBarMenu()
        ]
      ),
      body: new Column(
        children: <Widget>[
          new Flexible(
95
            child: new LazyBlock(
96
              key: new Key('main-scroll'),
97
              delegate: new FancyItemDelegate()
98 99 100 101 102 103 104 105 106 107 108 109 110 111
            )
          ),
          new BottomBar()
        ]
      ),
      drawer: new GalleryDrawer()
    );
  }
}

class TopBarMenu extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new PopupMenuButton<String>(
112
      onSelected: (String value) { print('Selected: $value'); },
113
      itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
114
        new PopupMenuItem<String>(
115 116
          value: 'Friends',
          child: new MenuItemWithIcon(Icons.people, 'Friends', '5 new')
117 118
        ),
        new PopupMenuItem<String>(
119 120
          value: 'Events',
          child: new MenuItemWithIcon(Icons.event, 'Events', '12 upcoming')
121 122
        ),
        new PopupMenuItem<String>(
123 124
          value: 'Events',
          child: new MenuItemWithIcon(Icons.group, 'Groups', '14')
125 126
        ),
        new PopupMenuItem<String>(
127 128
          value: 'Events',
          child: new MenuItemWithIcon(Icons.image, 'Pictures', '12')
129 130
        ),
        new PopupMenuItem<String>(
131 132
          value: 'Events',
          child: new MenuItemWithIcon(Icons.near_me, 'Nearby', '33')
133 134
        ),
        new PopupMenuItem<String>(
135 136
          value: 'Friends',
          child: new MenuItemWithIcon(Icons.people, 'Friends', '5')
137 138
        ),
        new PopupMenuItem<String>(
139 140
          value: 'Events',
          child: new MenuItemWithIcon(Icons.event, 'Events', '12')
141 142
        ),
        new PopupMenuItem<String>(
143 144
          value: 'Events',
          child: new MenuItemWithIcon(Icons.group, 'Groups', '14')
145 146
        ),
        new PopupMenuItem<String>(
147 148
          value: 'Events',
          child: new MenuItemWithIcon(Icons.image, 'Pictures', '12')
149 150
        ),
        new PopupMenuItem<String>(
151 152
          value: 'Events',
          child: new MenuItemWithIcon(Icons.near_me, 'Nearby', '33')
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
        )
      ]
    );
  }
}

class MenuItemWithIcon extends StatelessWidget {
  MenuItemWithIcon(this.icon, this.title, this.subtitle);

  final IconData icon;
  final String title;
  final String subtitle;

  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
Ian Hickson's avatar
Ian Hickson committed
170
        new Icon(icon),
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
        new Padding(
          padding: new EdgeInsets.only(left: 8.0, right: 8.0),
          child: new Text(title)
        ),
        new Text(subtitle, style: Theme.of(context).textTheme.caption)
      ]
    );
  }
}

class FancyImageItem extends StatelessWidget {
  FancyImageItem(this.index, {Key key}) : super(key: key);

  final int index;

  @override
  Widget build(BuildContext context) {
    return new BlockBody(
      children: <Widget>[
190
        new UserHeader('Ali Connors $index'),
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
        new ItemDescription(),
        new ItemImageBox(),
        new InfoBar(),
        new Padding(
          padding: new EdgeInsets.symmetric(horizontal: 8.0),
          child: new Divider()
        ),
        new IconBar(),
        new FatDivider()
      ]
    );
  }
}

class FancyGalleryItem extends StatelessWidget {
  FancyGalleryItem(this.index, {Key key}) : super(key: key);

  final int index;
  @override
  Widget build(BuildContext context) {
    return new BlockBody(
      children: <Widget>[
213
        new UserHeader('Ali Connors'),
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
        new ItemGalleryBox(index),
        new InfoBar(),
        new Padding(
          padding: new EdgeInsets.symmetric(horizontal: 8.0),
          child: new Divider()
        ),
        new IconBar(),
        new FatDivider()
      ]
    );
  }
}

class InfoBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.all(8.0),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
235 236
          new MiniIconWithText(Icons.thumb_up, '42'),
          new Text('3 Comments', style: Theme.of(context).textTheme.caption)
237 238 239 240 241 242 243 244 245 246 247 248 249 250
        ]
      )
    );
  }
}

class IconBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.only(left: 16.0, right: 16.0),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
251 252 253
          new IconWithText(Icons.thumb_up, 'Like'),
          new IconWithText(Icons.comment, 'Comment'),
          new IconWithText(Icons.share, 'Share'),
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
        ]
      )
    );
  }
}

class IconWithText extends StatelessWidget {
  IconWithText(this.icon, this.title);

  final IconData icon;
  final String title;

  @override
  Widget build(BuildContext context) {
    return new Row(
269
      mainAxisSize: MainAxisSize.min,
270
      children: <Widget>[
Ian Hickson's avatar
Ian Hickson committed
271 272 273 274
        new IconButton(
          icon: new Icon(icon),
          onPressed: () { print('Pressed $title button'); }
        ),
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
        new Text(title)
      ]
    );
  }
}

class MiniIconWithText extends StatelessWidget {
  MiniIconWithText(this.icon, this.title);

  final IconData icon;
  final String title;

  @override
  Widget build(BuildContext context) {
    return new Row(
290
      mainAxisSize: MainAxisSize.min,
291 292 293 294 295 296 297 298 299 300
      children: <Widget>[
        new Padding(
          padding: new EdgeInsets.only(right: 8.0),
          child: new Container(
            width: 16.0,
            height: 16.0,
            decoration: new BoxDecoration(
              backgroundColor: Theme.of(context).primaryColor,
              shape: BoxShape.circle
            ),
Ian Hickson's avatar
Ian Hickson committed
301
            child: new Icon(icon, color: Colors.white, size: 12.0)
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
          )
        ),
        new Text(title, style: Theme.of(context).textTheme.caption)
      ]
    );
  }
}

class FatDivider extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      height: 8.0,
      decoration: new BoxDecoration(
        backgroundColor: Theme.of(context).dividerColor
      )
    );
  }
}

class UserHeader extends StatelessWidget {
  UserHeader(this.userName);

  final String userName;

  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.all(8.0),
      child: new Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          new Padding(
            padding: new EdgeInsets.only(right: 8.0),
336 337
            child: new Image(
              image: new AssetImage('packages/flutter_gallery_assets/ali_connors_sml.png'),
338 339 340 341 342 343 344 345 346 347 348 349 350
              width: 32.0,
              height: 32.0
            )
          ),
          new Flexible(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                new RichText(text: new TextSpan(
                  style: Theme.of(context).textTheme.body1,
                  children: <TextSpan>[
                    new TextSpan(text: userName, style: new TextStyle(fontWeight: FontWeight.bold)),
351 352
                    new TextSpan(text: ' shared a new '),
                    new TextSpan(text: 'photo', style: new TextStyle(fontWeight: FontWeight.bold))
353 354 355 356
                  ]
                )),
                new Row(
                  children: <Widget>[
357
                    new Text('Yesterday at 11:55 • ', style: Theme.of(context).textTheme.caption),
Ian Hickson's avatar
Ian Hickson committed
358
                    new Icon(Icons.people, size: 16.0, color: Theme.of(context).textTheme.caption.color)
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
                  ]
                )
              ]
            )
          ),
          new TopBarMenu()
        ]
      )
    );
  }
}

class ItemDescription extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.all(8.0),
376
      child: new Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.')
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
    );
  }
}

class ItemImageBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.all(8.0),
      child: new Card(
        child: new Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            new Stack(
              children: <Widget>[
                new SizedBox(
                  height: 230.0,
394 395
                  child: new Image(
                    image: new AssetImage('packages/flutter_gallery_assets/top_10_australian_beaches.png')
396 397 398 399 400 401 402
                  )
                ),
                new Theme(
                  data: new ThemeData.dark(),
                  child: new Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: <Widget>[
Ian Hickson's avatar
Ian Hickson committed
403 404 405 406 407 408 409 410
                      new IconButton(
                        icon: new Icon(Icons.edit),
                        onPressed: () { print('Pressed edit button'); }
                      ),
                      new IconButton(
                        icon: new Icon(Icons.zoom_in),
                        onPressed: () { print('Pressed zoom button'); }
                      ),
411 412 413 414 415 416 417 418 419
                    ]
                  )
                ),
                new Positioned(
                  bottom: 4.0,
                  left: 4.0,
                  child: new Container(
                    decoration: new BoxDecoration(
                      backgroundColor: Colors.black54,
420
                      borderRadius: new BorderRadius.circular(2.0)
421 422 423 424 425 426 427
                    ),
                    padding: new EdgeInsets.all(4.0),
                    child: new RichText(
                      text: new TextSpan(
                        style: new TextStyle(color: Colors.white),
                        children: <TextSpan>[
                          new TextSpan(
428
                            text: 'Photo by '
429 430 431
                          ),
                          new TextSpan(
                            style: new TextStyle(fontWeight: FontWeight.bold),
432
                            text: 'Magic Mike'
433 434 435 436 437 438 439 440 441 442 443 444 445 446
                          )
                        ]
                      )
                    )
                  )
                )
              ]
            )
            ,
            new Padding(
              padding: new EdgeInsets.all(8.0),
              child: new Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>[
447 448 449
                  new Text('Where can you find that amazing sunset?', style: Theme.of(context).textTheme.body2),
                  new Text('The sun sets over stinson beach', style: Theme.of(context).textTheme.body1),
                  new Text('flutter.io/amazingsunsets', style: Theme.of(context).textTheme.caption)
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
                ]
              )
            )
          ]
        )
      )
    );
  }
}

class ItemGalleryBox extends StatelessWidget {
  ItemGalleryBox(this.index);

  final int index;

  @override
  Widget build(BuildContext context) {
    List<String> tabNames = <String>[
468
      'A', 'B', 'C', 'D'
469 470 471 472 473 474 475 476 477
    ];

    return new SizedBox(
      height: 200.0,
      child: new TabBarSelection<String>(
        values: tabNames,
        child: new Column(
          children: <Widget>[
            new Flexible(
478
              child: new TabBarView<String>(
479 480
                children: tabNames.map((String tabName) {
                  return new Container(
481
                    key: new Key('Tab $index - $tabName'),
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
                    child: new Padding(
                      padding: new EdgeInsets.all(8.0),
                      child: new Card(
                        child: new Column(
                          children: <Widget>[
                            new Flexible(
                              child: new Container(
                                decoration: new BoxDecoration(
                                  backgroundColor: Theme.of(context).primaryColor
                                ),
                                child: new Center(
                                  child: new Text(tabName, style: Theme.of(context).textTheme.headline.copyWith(color: Colors.white))
                                )
                              )
                            ),
                            new Row(
                              children: <Widget>[
                                new IconButton(
Ian Hickson's avatar
Ian Hickson committed
500
                                  icon: new Icon(Icons.share),
501
                                  onPressed: () { print('Pressed share'); }
502 503
                                ),
                                new IconButton(
Ian Hickson's avatar
Ian Hickson committed
504
                                  icon: new Icon(Icons.event),
505
                                  onPressed: () { print('Pressed event'); }
506 507 508 509
                                ),
                                new Flexible(
                                  child: new Padding(
                                    padding: new EdgeInsets.only(left: 8.0),
510
                                    child: new Text('This is item $tabName')
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
                                  )
                                )
                              ]
                            )
                          ]
                        )
                      )
                    )
                  );
                }).toList()
              )
            ),
            new Container(
              child: new TabPageSelector<String>()
            )
          ]
        )
      )
    );
  }
}

class BottomBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      decoration: new BoxDecoration(
        border: new Border(
          top: new BorderSide(
            color: Theme.of(context).dividerColor,
            width: 1.0
          )
        )
      ),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
548 549 550 551 552
          new BottomBarButton(Icons.new_releases, 'News'),
          new BottomBarButton(Icons.people, 'Requests'),
          new BottomBarButton(Icons.chat, 'Messenger'),
          new BottomBarButton(Icons.bookmark, 'Bookmark'),
          new BottomBarButton(Icons.alarm, 'Alarm')
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
        ]
      )
    );
  }
}

class BottomBarButton extends StatelessWidget {
  BottomBarButton(this.icon, this.title);

  final IconData icon;
  final String title;

  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.all(8.0),
      child: new Column(
        children: <Widget>[
          new IconButton(
Ian Hickson's avatar
Ian Hickson committed
572
            icon: new Icon(icon),
573
            onPressed: () { print('Pressed: $title'); }
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
          ),
          new Text(title, style: Theme.of(context).textTheme.caption)
        ]
      )
    );
  }
}

class GalleryDrawer extends StatelessWidget {
  GalleryDrawer({ Key key }) : super(key: key);

  void _changeTheme(BuildContext context, bool value) {
    ComplexLayoutApp.of(context).lightTheme = value;
  }

  @override
  Widget build(BuildContext context) {
    return new Drawer(
      child: new Block(
        children: <Widget>[
          new FancyDrawerHeader(),
          new DrawerItem(
Ian Hickson's avatar
Ian Hickson committed
596
            icon: new Icon(Icons.brightness_5),
597 598 599 600 601 602 603 604 605 606 607 608 609 610
            onPressed: () { _changeTheme(context, true); },
            selected: ComplexLayoutApp.of(context).lightTheme,
            child: new Row(
              children: <Widget>[
                new Flexible(child: new Text('Light')),
                new Radio<bool>(
                  value: true,
                  groupValue: ComplexLayoutApp.of(context).lightTheme,
                  onChanged: (bool value) { _changeTheme(context, value); }
                )
              ]
            )
          ),
          new DrawerItem(
Ian Hickson's avatar
Ian Hickson committed
611
            icon: new Icon(Icons.brightness_7),
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
            onPressed: () { _changeTheme(context, false); },
            selected: !ComplexLayoutApp.of(context).lightTheme,
            child: new Row(
              children: <Widget>[
                new Flexible(child: new Text('Dark')),
                new Radio<bool>(
                  value: false,
                  groupValue: ComplexLayoutApp.of(context).lightTheme,
                  onChanged: (bool value) { _changeTheme(context, value); }
                )
              ]
            )
          ),
          new Divider(),
          new DrawerItem(
Ian Hickson's avatar
Ian Hickson committed
627
            icon: new Icon(Icons.hourglass_empty),
628
            selected: timeDilation != 1.0,
629
            onPressed: () { ComplexLayoutApp.of(context).toggleAnimationSpeed(); },
630 631 632 633 634
            child: new Row(
              children: <Widget>[
                new Flexible(child: new Text('Animate Slowly')),
                new Checkbox(
                  value: timeDilation != 1.0,
635
                  onChanged: (bool value) { ComplexLayoutApp.of(context).toggleAnimationSpeed(); }
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
                )
              ]
            )
          )
        ]
      )
    );
  }
}

class FancyDrawerHeader extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      decoration: new BoxDecoration(
        backgroundColor: Colors.purple[500]
      ),
      height: 200.0
    );
  }
}