mirror of https://github.com/flutter/samples.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
4.6 KiB
173 lines
4.6 KiB
// Copyright 2018 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_web/material.dart';
|
|
|
|
import 'sections.dart';
|
|
|
|
const double kSectionIndicatorWidth = 32.0;
|
|
|
|
// The card for a single section. Displays the section's gradient and background image.
|
|
class SectionCard extends StatelessWidget {
|
|
const SectionCard({Key key, @required this.section})
|
|
: assert(section != null),
|
|
super(key: key);
|
|
|
|
final Section section;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Semantics(
|
|
label: section.title,
|
|
button: true,
|
|
child: DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.centerLeft,
|
|
end: Alignment.centerRight,
|
|
colors: <Color>[
|
|
section.leftColor,
|
|
section.rightColor,
|
|
],
|
|
),
|
|
),
|
|
// TODO(b:119312219): Remove Opacity layer when Image Color Filter
|
|
// is implemented in paintImage.
|
|
child: Opacity(
|
|
opacity: 0.075,
|
|
child: Image.asset(
|
|
section.backgroundAsset,
|
|
package: section.backgroundAssetPackage,
|
|
color: const Color.fromRGBO(255, 255, 255, 0.075),
|
|
colorBlendMode: BlendMode.modulate,
|
|
fit: BoxFit.cover,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// The title is rendered with two overlapping text widgets that are vertically
|
|
// offset a little. It's supposed to look sort-of 3D.
|
|
class SectionTitle extends StatelessWidget {
|
|
const SectionTitle({
|
|
Key key,
|
|
@required this.section,
|
|
@required this.scale,
|
|
@required this.opacity,
|
|
}) : assert(section != null),
|
|
assert(scale != null),
|
|
assert(opacity != null && opacity >= 0.0 && opacity <= 1.0),
|
|
super(key: key);
|
|
|
|
final Section section;
|
|
final double scale;
|
|
final double opacity;
|
|
|
|
static const TextStyle sectionTitleStyle = TextStyle(
|
|
fontFamily: 'Raleway',
|
|
inherit: false,
|
|
fontSize: 24.0,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.white,
|
|
textBaseline: TextBaseline.alphabetic,
|
|
);
|
|
|
|
static final TextStyle sectionTitleShadowStyle = sectionTitleStyle.copyWith(
|
|
color: const Color(0x19000000),
|
|
);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return IgnorePointer(
|
|
child: Opacity(
|
|
opacity: opacity,
|
|
child: Transform(
|
|
transform: Matrix4.identity()..scale(scale),
|
|
alignment: Alignment.center,
|
|
child: Stack(
|
|
children: <Widget>[
|
|
Positioned(
|
|
top: 4.0,
|
|
child: Text(section.title, style: sectionTitleShadowStyle),
|
|
),
|
|
Text(section.title, style: sectionTitleStyle),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Small horizontal bar that indicates the selected section.
|
|
class SectionIndicator extends StatelessWidget {
|
|
const SectionIndicator({Key key, this.opacity = 1.0}) : super(key: key);
|
|
|
|
final double opacity;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return IgnorePointer(
|
|
child: Container(
|
|
width: kSectionIndicatorWidth,
|
|
height: 3.0,
|
|
color: Colors.white.withOpacity(opacity),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Display a single SectionDetail.
|
|
class SectionDetailView extends StatelessWidget {
|
|
SectionDetailView({Key key, @required this.detail})
|
|
: assert(detail != null && detail.imageAsset != null),
|
|
assert((detail.imageAsset ?? detail.title) != null),
|
|
super(key: key);
|
|
|
|
final SectionDetail detail;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final Widget image = DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(6.0),
|
|
image: DecorationImage(
|
|
image: AssetImage(
|
|
detail.imageAsset,
|
|
package: detail.imageAssetPackage,
|
|
),
|
|
fit: BoxFit.cover,
|
|
alignment: Alignment.center,
|
|
),
|
|
),
|
|
);
|
|
|
|
Widget item;
|
|
if (detail.title == null && detail.subtitle == null) {
|
|
item = Container(
|
|
height: 240.0,
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: SafeArea(
|
|
top: false,
|
|
bottom: false,
|
|
child: image,
|
|
),
|
|
);
|
|
} else {
|
|
item = ListTile(
|
|
title: Text(detail.title),
|
|
subtitle: Text(detail.subtitle),
|
|
leading: SizedBox(width: 32.0, height: 32.0, child: image),
|
|
);
|
|
}
|
|
|
|
return DecoratedBox(
|
|
decoration: BoxDecoration(color: Colors.grey.shade200),
|
|
child: item,
|
|
);
|
|
}
|
|
}
|