blob: 03bcec4b0c7ffd4bb9317220a11781ff7222a3fc [file] [log] [blame]
// Copyright 2019-present the Flutter authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import 'package:flutter/material.dart';
import 'package:flutter_gallery/demo/rally/charts/pie_chart.dart';
import 'package:flutter_gallery/demo/rally/charts/line_chart.dart';
import 'package:flutter_gallery/demo/rally/charts/vertical_fraction_bar.dart';
import 'package:flutter_gallery/demo/rally/colors.dart';
import 'package:flutter_gallery/demo/rally/data.dart';
import 'package:flutter_gallery/demo/rally/formatters.dart';
class FinancialEntityView extends StatelessWidget {
const FinancialEntityView({
this.heroLabel,
this.heroAmount,
this.wholeAmount,
this.segments,
this.financialEntityCards,
}) : assert(segments.length == financialEntityCards.length);
/// The amounts to assign each item.
final List<RallyPieChartSegment> segments;
final String heroLabel;
final double heroAmount;
final double wholeAmount;
final List<FinancialEntityCategoryView> financialEntityCards;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
RallyPieChart(
heroLabel: heroLabel,
heroAmount: heroAmount,
wholeAmount: wholeAmount,
segments: segments,
),
SizedBox(
height: 1,
child: Container(
color: const Color(0xA026282F),
),
),
ListView(shrinkWrap: true, children: financialEntityCards),
],
);
}
}
/// A reusable widget to show balance information of a single entity as a card.
class FinancialEntityCategoryView extends StatelessWidget {
const FinancialEntityCategoryView({
@required this.indicatorColor,
@required this.indicatorFraction,
@required this.title,
@required this.subtitle,
@required this.amount,
@required this.suffix,
});
final Color indicatorColor;
final double indicatorFraction;
final String title;
final String subtitle;
final double amount;
final Widget suffix;
@override
Widget build(BuildContext context) {
return FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<FinancialEntityCategoryDetailsPage>(
builder: (BuildContext context) => FinancialEntityCategoryDetailsPage(),
),
);
},
child: SizedBox(
height: 68,
child: Column(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 12, right: 12),
child: VerticalFractionBar(
color: indicatorColor,
fraction: indicatorFraction,
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
title,
style: Theme.of(context).textTheme.body1.copyWith(fontSize: 16),
),
Text(
subtitle,
style: Theme.of(context).textTheme.body1.copyWith(color: RallyColors.gray60),
),
],
),
const Spacer(),
Text(
'\$ ' + usdFormat.format(amount),
style: Theme.of(context).textTheme.body2.copyWith(fontSize: 20, color: RallyColors.gray),
),
SizedBox(width: 32, child: suffix),
],
),
),
const Divider(
height: 1,
indent: 16,
endIndent: 16,
color: Color(0xAA282828),
),
],
),
),
);
}
}
/// Data model for [FinancialEntityCategoryView].
class FinancialEntityCategoryModel {
const FinancialEntityCategoryModel(
this.indicatorColor,
this.indicatorFraction,
this.title,
this.subtitle,
this.usdAmount,
this.suffix,
);
final Color indicatorColor;
final double indicatorFraction;
final String title;
final String subtitle;
final double usdAmount;
final Widget suffix;
}
FinancialEntityCategoryView buildFinancialEntityFromAccountData(
AccountData model,
int accountDataIndex,
) {
return FinancialEntityCategoryView(
suffix: const Icon(Icons.chevron_right, color: Colors.grey),
title: model.name,
subtitle: '• • • • • • ${model.accountNumber.substring(6)}',
indicatorColor: RallyColors.accountColor(accountDataIndex),
indicatorFraction: 1,
amount: model.primaryAmount,
);
}
FinancialEntityCategoryView buildFinancialEntityFromBillData(
BillData model,
int billDataInex,
) {
return FinancialEntityCategoryView(
suffix: const Icon(Icons.chevron_right, color: Colors.grey),
title: model.name,
subtitle: model.dueDate,
indicatorColor: RallyColors.billColor(billDataInex),
indicatorFraction: 1,
amount: model.primaryAmount,
);
}
FinancialEntityCategoryView buildFinancialEntityFromBudgetData(
BudgetData item,
int budgetDataIndex,
BuildContext context,
) {
final String amountUsed = usdWithSignFormat.format(item.amountUsed);
final String primaryAmount = usdWithSignFormat.format(item.primaryAmount);
return FinancialEntityCategoryView(
suffix: Text(
' LEFT',
style: Theme.of(context).textTheme.body1.copyWith(color: RallyColors.gray60, fontSize: 10),
),
title: item.name,
subtitle: amountUsed + ' / ' + primaryAmount,
indicatorColor: RallyColors.budgetColor(budgetDataIndex),
indicatorFraction: item.amountUsed / item.primaryAmount,
amount: item.primaryAmount - item.amountUsed,
);
}
List<FinancialEntityCategoryView> buildAccountDataListViews(
List<AccountData> items) {
return List<FinancialEntityCategoryView>.generate(
items.length,
(int i) => buildFinancialEntityFromAccountData(items[i], i),
);
}
List<FinancialEntityCategoryView> buildBillDataListViews(List<BillData> items) {
return List<FinancialEntityCategoryView>.generate(
items.length,
(int i) => buildFinancialEntityFromBillData(items[i], i),
);
}
List<FinancialEntityCategoryView> buildBudgetDataListViews(
List<BudgetData> items, BuildContext context) {
return <FinancialEntityCategoryView>[
for (int i = 0; i < items.length; i++)
buildFinancialEntityFromBudgetData(items[i], i, context)
];
}
class FinancialEntityCategoryDetailsPage extends StatelessWidget {
final List<DetailedEventData> items = DummyDataService.getDetailedEventItems();
@override
Widget build(BuildContext context) {
final List<_DetailedEventCard> cards = items.map((DetailedEventData detailedEventData) {
return _DetailedEventCard(
title: detailedEventData.title,
subtitle: dateFormat.format(detailedEventData.date),
amount: detailedEventData.amount,
);
}).toList();
return Scaffold(
appBar: AppBar(
elevation: 0,
centerTitle: true,
title: Text(
'Checking',
style: Theme.of(context).textTheme.body1.copyWith(fontSize: 18),
),
),
body: Column(
children: <Widget>[
SizedBox(
height: 200,
width: double.infinity,
child: RallyLineChart(events: items),
),
Flexible(
child: ListView(shrinkWrap: true, children: cards),
),
],
),
);
}
}
class _DetailedEventCard extends StatelessWidget {
const _DetailedEventCard({
@required this.title,
@required this.subtitle,
@required this.amount,
});
final String title;
final String subtitle;
final double amount;
@override
Widget build(BuildContext context) {
final TextTheme textTheme = Theme.of(context).textTheme;
return FlatButton(
onPressed: () {},
child: SizedBox(
height: 68,
child: Column(
children: <Widget>[
SizedBox(
height: 67,
child: Row(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
title,
style: textTheme.body1.copyWith(fontSize: 16),
),
Text(
subtitle,
style: textTheme.body1.copyWith(color: RallyColors.gray60),
)
],
),
const Spacer(),
Text(
'\$${usdFormat.format(amount)}',
style: textTheme.body2.copyWith(fontSize: 20, color: RallyColors.gray),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: SizedBox(
height: 1,
child: Container(
color: const Color(0xAA282828),
),
),
),
],
),
),
);
}
}