blob: ab3d818286b03718ac4e7abf42d7e38ceaf6a5f6 [file] [log] [blame]
// Copyright 2014 The Flutter 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:intl/intl.dart';
import 'package:scoped_model/scoped_model.dart';
import 'package:flutter_gallery/demo/shrine/colors.dart';
import 'package:flutter_gallery/demo/shrine/expanding_bottom_sheet.dart';
import 'package:flutter_gallery/demo/shrine/model/app_state_model.dart';
import 'package:flutter_gallery/demo/shrine/model/product.dart';
const double _leftColumnWidth = 60.0;
class ShoppingCartPage extends StatefulWidget {
const ShoppingCartPage({Key? key}) : super(key: key);
@override
_ShoppingCartPageState createState() => _ShoppingCartPageState();
}
class _ShoppingCartPageState extends State<ShoppingCartPage> {
List<Widget> _createShoppingCartRows(AppStateModel model) {
return model.productsInCart.keys
.map((int id) => ShoppingCartRow(
product: model.getProductById(id),
quantity: model.productsInCart[id],
onPressed: () {
model.removeItemFromCart(id);
},
),
)
.toList();
}
@override
Widget build(BuildContext context) {
final ThemeData localTheme = Theme.of(context);
return Scaffold(
backgroundColor: kShrinePink50,
body: SafeArea(
child: ScopedModelDescendant<AppStateModel>(
builder: (BuildContext context, Widget? child, AppStateModel model) {
return Stack(
children: <Widget>[
ListView(
children: <Widget>[
Row(
children: <Widget>[
SizedBox(
width: _leftColumnWidth,
child: IconButton(
icon: const Icon(Icons.keyboard_arrow_down),
onPressed: () => ExpandingBottomSheet.of(context)!.close(),
),
),
Text(
'CART',
style: localTheme.textTheme.subtitle1!.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(width: 16.0),
Text('${model.totalCartQuantity} ITEMS'),
],
),
const SizedBox(height: 16.0),
Column(
children: _createShoppingCartRows(model),
),
ShoppingCartSummary(model: model),
const SizedBox(height: 100.0),
],
),
Positioned(
bottom: 16.0,
left: 16.0,
right: 16.0,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: kShrinePink100,
shape: const BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(7.0)),
),
),
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: Text('CLEAR CART'),
),
onPressed: () {
model.clearCart();
ExpandingBottomSheet.of(context)!.close();
},
),
),
],
);
},
),
),
);
}
}
class ShoppingCartSummary extends StatelessWidget {
const ShoppingCartSummary({Key? key, this.model}) : super(key: key);
final AppStateModel? model;
@override
Widget build(BuildContext context) {
final TextStyle smallAmountStyle = Theme.of(context).textTheme.bodyText2!.copyWith(color: kShrineBrown600);
final TextStyle? largeAmountStyle = Theme.of(context).textTheme.headline4;
final NumberFormat formatter = NumberFormat.simpleCurrency(
decimalDigits: 2,
locale: Localizations.localeOf(context).toString(),
);
return Row(
children: <Widget>[
const SizedBox(width: _leftColumnWidth),
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const Expanded(
child: Text('TOTAL'),
),
Text(
formatter.format(model!.totalCost),
style: largeAmountStyle,
),
],
),
const SizedBox(height: 16.0),
Row(
children: <Widget>[
const Expanded(
child: Text('Subtotal:'),
),
Text(
formatter.format(model!.subtotalCost),
style: smallAmountStyle,
),
],
),
const SizedBox(height: 4.0),
Row(
children: <Widget>[
const Expanded(
child: Text('Shipping:'),
),
Text(
formatter.format(model!.shippingCost),
style: smallAmountStyle,
),
],
),
const SizedBox(height: 4.0),
Row(
children: <Widget>[
const Expanded(
child: Text('Tax:'),
),
Text(
formatter.format(model!.tax),
style: smallAmountStyle,
),
],
),
],
),
),
),
],
);
}
}
class ShoppingCartRow extends StatelessWidget {
const ShoppingCartRow({
Key? key,
required this.product,
required this.quantity,
this.onPressed,
}) : super(key: key);
final Product product;
final int? quantity;
final VoidCallback? onPressed;
@override
Widget build(BuildContext context) {
final NumberFormat formatter = NumberFormat.simpleCurrency(
decimalDigits: 0,
locale: Localizations.localeOf(context).toString(),
);
final ThemeData localTheme = Theme.of(context);
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: Row(
key: ValueKey<int>(product.id),
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
width: _leftColumnWidth,
child: IconButton(
icon: const Icon(Icons.remove_circle_outline),
onPressed: onPressed,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset(
product.assetName,
package: product.assetPackage,
fit: BoxFit.cover,
width: 75.0,
height: 75.0,
),
const SizedBox(width: 16.0),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Text('Quantity: $quantity'),
),
Text('x ${formatter.format(product.price)}'),
],
),
Text(
product.name,
style: localTheme.textTheme.subtitle1!.copyWith(fontWeight: FontWeight.w600),
),
],
),
),
],
),
const SizedBox(height: 16.0),
const Divider(
color: kShrineBrown900,
height: 10.0,
),
],
),
),
),
],
),
);
}
}