Skip to content

Commit

Permalink
[Gallery] Crane focus (flutter#254)
Browse files Browse the repository at this point in the history
* Add debugLabel to HighlightFocus

* Remove decrated property

* Add focus to DestinationCards

* Add index property to Forms

* Move BackLayer stuff to its own file

* Add focus

* Revert deprecated change

* Address feedback


Former-commit-id: 49c7244
  • Loading branch information
guidezpl authored Jan 24, 2020
1 parent ba36175 commit c70ad4f
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 107 deletions.
4 changes: 4 additions & 0 deletions gallery/lib/layout/highlight_focus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class HighlightFocus extends StatefulWidget {
this.highlightColor,
this.borderColor,
this.hasFocus = true,
this.debugLabel,
});

/// [onPressed] is called when you press space, enter, or numpad-enter
Expand All @@ -37,6 +38,8 @@ class HighlightFocus extends StatefulWidget {
/// Set to false if you want the child to skip focus.
final bool hasFocus;

final String debugLabel;

@override
_HighlightFocusState createState() => _HighlightFocusState();
}
Expand Down Expand Up @@ -67,6 +70,7 @@ class _HighlightFocusState extends State<HighlightFocus> {

return Focus(
canRequestFocus: widget.hasFocus,
debugLabel: widget.debugLabel,
onFocusChange: (newValue) {
setState(() {
isFocused = newValue;
Expand Down
8 changes: 4 additions & 4 deletions gallery/lib/studies/crane/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ class _CraneAppState extends State<CraneApp> {
home: ApplyTextOptions(
child: Backdrop(
frontLayer: Container(),
backLayer: [
FlyForm(),
SleepForm(),
EatForm(),
backLayerItems: [
FlyForm(index: 0),
SleepForm(index: 1),
EatForm(index: 2),
],
frontTitle: Text('CRANE'),
backTitle: Text('MENU'),
Expand Down
180 changes: 82 additions & 98 deletions gallery/lib/studies/crane/backdrop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:gallery/data/gallery_options.dart';
import 'package:gallery/l10n/gallery_localizations.dart';
import 'package:gallery/layout/adaptive.dart';
import 'package:gallery/studies/crane/border_tab_indicator.dart';
import 'package:gallery/studies/crane/backlayer.dart';
import 'package:gallery/studies/crane/colors.dart';
import 'package:gallery/studies/crane/item_cards.dart';

Expand All @@ -32,26 +33,29 @@ class _FrontLayer extends StatelessWidget {
Widget build(BuildContext context) {
final isDesktop = isDisplayDesktop(context);

return PhysicalShape(
elevation: 16,
color: cranePrimaryWhite,
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(frontLayerBorderRadius),
topRight: Radius.circular(frontLayerBorderRadius),
return DefaultFocusTraversal(
policy: ReadingOrderTraversalPolicy(),
child: PhysicalShape(
elevation: 16,
color: cranePrimaryWhite,
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(frontLayerBorderRadius),
topRight: Radius.circular(frontLayerBorderRadius),
),
),
),
),
child: ListView(
padding: isDesktop
? EdgeInsets.symmetric(horizontal: 120, vertical: 22)
: EdgeInsets.all(20),
children: [
Text(title, style: Theme.of(context).textTheme.subtitle),
SizedBox(height: 20),
ItemCards(index: index),
],
child: ListView(
padding: isDesktop
? EdgeInsets.symmetric(horizontal: 120, vertical: 22)
: EdgeInsets.all(20),
children: [
Text(title, style: Theme.of(context).textTheme.subtitle),
SizedBox(height: 20),
ItemCards(index: index),
],
),
),
);
}
Expand All @@ -65,17 +69,17 @@ class _FrontLayer extends StatelessWidget {
/// front or back layer is showing.
class Backdrop extends StatefulWidget {
final Widget frontLayer;
final List<Widget> backLayer;
final List<BackLayerItem> backLayerItems;
final Widget frontTitle;
final Widget backTitle;

const Backdrop({
@required this.frontLayer,
@required this.backLayer,
@required this.backLayerItems,
@required this.frontTitle,
@required this.backTitle,
}) : assert(frontLayer != null),
assert(backLayer != null),
assert(backLayerItems != null),
assert(frontTitle != null),
assert(backTitle != null);

Expand Down Expand Up @@ -125,95 +129,75 @@ class _BackdropState extends State<Backdrop> with TickerProviderStateMixin {
color: cranePurple800,
child: Padding(
padding: EdgeInsets.only(top: 12),
child: Scaffold(
backgroundColor: cranePurple800,
appBar: AppBar(
brightness: Brightness.dark,
elevation: 0,
titleSpacing: 0,
flexibleSpace: CraneAppBar(
tabController: _tabController,
tabHandler: _handleTabs,
),
),
body: Stack(
children: [
BackLayer(
child: DefaultFocusTraversal(
policy: ReadingOrderTraversalPolicy(),
child: Scaffold(
backgroundColor: cranePurple800,
appBar: AppBar(
brightness: Brightness.dark,
elevation: 0,
titleSpacing: 0,
flexibleSpace: CraneAppBar(
tabController: _tabController,
backLayers: widget.backLayer,
tabHandler: _handleTabs,
),
Container(
margin: EdgeInsets.only(
top: isDesktop
? 60 + 20 * textScaleFactor / 2
: 175 + 140 * textScaleFactor / 2,
),
child: TabBarView(
physics: isDesktop
? NeverScrollableScrollPhysics()
: null, // use default TabBarView physics
controller: _tabController,
children: [
SlideTransition(
position: _flyLayerOffset,
child: _FrontLayer(
title: GalleryLocalizations.of(context).craneFlySubhead,
index: 0,
),
),
SlideTransition(
position: _sleepLayerOffset,
child: _FrontLayer(
title:
GalleryLocalizations.of(context).craneSleepSubhead,
index: 1,
),
),
body: FocusScope(
child: Stack(
children: [
BackLayer(
tabController: _tabController,
backLayerItems: widget.backLayerItems,
),
Container(
margin: EdgeInsets.only(
top: isDesktop
? 60 + 20 * textScaleFactor / 2
: 175 + 140 * textScaleFactor / 2,
),
SlideTransition(
position: _eatLayerOffset,
child: _FrontLayer(
title: GalleryLocalizations.of(context).craneEatSubhead,
index: 2,
),
child: TabBarView(
physics: isDesktop
? NeverScrollableScrollPhysics()
: null, // use default TabBarView physics
controller: _tabController,
children: [
SlideTransition(
position: _flyLayerOffset,
child: _FrontLayer(
title: GalleryLocalizations.of(context)
.craneFlySubhead,
index: 0,
),
),
SlideTransition(
position: _sleepLayerOffset,
child: _FrontLayer(
title: GalleryLocalizations.of(context)
.craneSleepSubhead,
index: 1,
),
),
SlideTransition(
position: _eatLayerOffset,
child: _FrontLayer(
title: GalleryLocalizations.of(context)
.craneEatSubhead,
index: 2,
),
),
],
),
],
),
),
],
),
],
),
),
),
),
);
}
}

class BackLayer extends StatefulWidget {
final List<Widget> backLayers;
final TabController tabController;

const BackLayer({Key key, this.backLayers, this.tabController})
: super(key: key);

@override
_BackLayerState createState() => _BackLayerState();
}

class _BackLayerState extends State<BackLayer> {
@override
void initState() {
super.initState();
widget.tabController.addListener(() => setState(() {}));
}

@override
Widget build(BuildContext context) {
return IndexedStack(
index: widget.tabController.index,
children: widget.backLayers,
);
}
}

class CraneAppBar extends StatefulWidget {
final Function(int) tabHandler;
final TabController tabController;
Expand Down
49 changes: 49 additions & 0 deletions gallery/lib/studies/crane/backlayer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2019 The Flutter team. 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';

abstract class BackLayerItem extends StatefulWidget {
final int index;

BackLayerItem({Key key, this.index}) : super(key: key);
}

class BackLayer extends StatefulWidget {
final List<BackLayerItem> backLayerItems;
final TabController tabController;

const BackLayer({Key key, this.backLayerItems, this.tabController})
: super(key: key);

@override
_BackLayerState createState() => _BackLayerState();
}

class _BackLayerState extends State<BackLayer> {
@override
void initState() {
super.initState();
widget.tabController.addListener(() => setState(() {}));
}

@override
Widget build(BuildContext context) {
final tabIndex = widget.tabController.index;
return DefaultFocusTraversal(
policy: WidgetOrderFocusTraversalPolicy(),
child: IndexedStack(
index: tabIndex,
children: [
for (BackLayerItem backLayerItem in widget.backLayerItems)
Focus(
canRequestFocus: backLayerItem.index == tabIndex,
debugLabel: 'backLayerItem: $backLayerItem',
child: backLayerItem,
)
],
),
);
}
}
5 changes: 4 additions & 1 deletion gallery/lib/studies/crane/eat_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
import 'package:flutter/material.dart';

import 'package:gallery/l10n/gallery_localizations.dart';
import 'package:gallery/studies/crane/backlayer.dart';
import 'package:gallery/studies/crane/header_form.dart';

class EatForm extends StatefulWidget {
class EatForm extends BackLayerItem {
EatForm({int index}) : super(index: index);

@override
_EatFormState createState() => _EatFormState();
}
Expand Down
5 changes: 4 additions & 1 deletion gallery/lib/studies/crane/fly_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
import 'package:flutter/material.dart';

import 'package:gallery/l10n/gallery_localizations.dart';
import 'package:gallery/studies/crane/backlayer.dart';
import 'package:gallery/studies/crane/header_form.dart';

class FlyForm extends StatefulWidget {
class FlyForm extends BackLayerItem {
FlyForm({int index}) : super(index: index);

@override
_FlyFormState createState() => _FlyFormState();
}
Expand Down
10 changes: 8 additions & 2 deletions gallery/lib/studies/crane/item_cards.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:gallery/layout/adaptive.dart';
import 'package:gallery/layout/highlight_focus.dart';
import 'package:gallery/studies/crane/model/data.dart';
import 'package:gallery/studies/crane/model/destination.dart';

Expand Down Expand Up @@ -33,8 +34,13 @@ class _ItemCardsState extends State<ItemCards> {

return destinations
.map(
(d) => RepaintBoundary(
child: _DestinationCard(destination: d),
(d) => HighlightFocus(
debugLabel: 'DestinationCard: ${d.destination}',
highlightColor: Colors.red.withOpacity(0.5),
onPressed: () {},
child: RepaintBoundary(
child: _DestinationCard(destination: d),
),
),
)
.toList();
Expand Down
5 changes: 4 additions & 1 deletion gallery/lib/studies/crane/sleep_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
import 'package:flutter/material.dart';
import 'package:gallery/l10n/gallery_localizations.dart';

import 'package:gallery/studies/crane/backlayer.dart';
import 'package:gallery/studies/crane/header_form.dart';

class SleepForm extends StatefulWidget {
class SleepForm extends BackLayerItem {
SleepForm({int index}) : super(index: index);

@override
_SleepFormState createState() => _SleepFormState();
}
Expand Down

0 comments on commit c70ad4f

Please sign in to comment.