Skip to content

Commit

Permalink
[Presentation] [WIP] Initial ui
Browse files Browse the repository at this point in the history
  • Loading branch information
Wolfteam committed May 6, 2022
1 parent e92478f commit 4ebcf24
Show file tree
Hide file tree
Showing 12 changed files with 671 additions and 2 deletions.
11 changes: 10 additions & 1 deletion lib/l10n/intl_en.arb
Expand Up @@ -428,5 +428,14 @@
"versionDesc": "Version desc.",
"releaseHistory": "Release History",
"selectAnOption": "Select an option",
"details": "Details"
"details": "Details",
"charts": "Charts",
"birthdays": "Birthdays",
"topCharacters": "Top characters",
"topWeapons": "Top weapons",
"xStarsWithMostReruns": "{xStars} with most reruns",
"xStarsWithLeastReruns": "{xStars} with least reruns",
"birthdaysPerMonth": "Birthdays per month",
"mostAndLeastReleased": "Most and least released",
"mostAndLeastRepeated": "Most and least repeated"
}
204 changes: 204 additions & 0 deletions lib/presentation/charts/charts_page.dart
@@ -0,0 +1,204 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:shiori/application/bloc.dart';
import 'package:shiori/domain/enums/enums.dart';
import 'package:shiori/domain/extensions/iterable_extensions.dart';
import 'package:shiori/generated/l10n.dart';
import 'package:shiori/injection.dart';
import 'package:shiori/presentation/character/character_page.dart';
import 'package:shiori/presentation/charts/widgets/chart_card.dart';
import 'package:shiori/presentation/charts/widgets/chart_legend.dart';
import 'package:shiori/presentation/charts/widgets/horizontal_bar_chart.dart';
import 'package:shiori/presentation/charts/widgets/pie_chart.dart';
import 'package:shiori/presentation/charts/widgets/vertical_bar_chart.dart';
import 'package:shiori/presentation/shared/extensions/element_type_extensions.dart';
import 'package:shiori/presentation/shared/extensions/i18n_extensions.dart';
import 'package:shiori/presentation/shared/loading.dart';
import 'package:shiori/presentation/shared/styles.dart';
import 'package:shiori/presentation/weapon/weapon_page.dart';

const double _topCardWidth = 350;
const double _topCardHeight = 300;
const double _topCardBoxHeight = _topCardHeight + 20;

const _topCharacterTypes = [
ChartType.topFiveStarCharacterMostReruns,
ChartType.topFiveStarCharacterLeastReruns,
ChartType.topFourStarCharacterMostReruns,
ChartType.topFourStarCharacterLeastReruns,
];

const _topWeaponTypes = [
ChartType.topFiveStarWeaponMostReruns,
ChartType.topFiveStarWeaponLeastReruns,
ChartType.topFourStarWeaponMostReruns,
ChartType.topFourStarWeaponLeastReruns,
];

const _topCharacterColors = [Colors.red, Colors.orange, Colors.yellow, Colors.green, Colors.blue];
const _topWeaponColors = [Colors.red, Colors.orange, Colors.yellow, Colors.green, Colors.blue];

class ChartsPage extends StatelessWidget {
const ChartsPage({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final mq = MediaQuery.of(context);
final s = S.of(context);

final now = DateTime.now();
final formatter = DateFormat('MMM');
final List<String> months = List.generate(DateTime.monthsPerYear, (int index) {
final date = DateTime(now.year, index + 1);
return formatter.format(date);
});

return BlocProvider<ChartsBloc>(
create: (context) => Injection.chartsBloc..add(const ChartsEvent.init()),
child: Scaffold(
appBar: AppBar(
title: Text(s.charts),
),
body: SingleChildScrollView(
child: Padding(
padding: Styles.edgeInsetAll5,
child: BlocBuilder<ChartsBloc, ChartsState>(
builder: (context, state) => state.map(
loading: (_) => const Loading(useScaffold: false),
initial: (state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(s.topCharacters, style: theme.textTheme.headline5),
SizedBox(
height: _topCardBoxHeight,
//TODO: SPACE BETWEEN ITEMS
child: ListView.builder(
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: _topCharacterTypes.length,
itemBuilder: (ctx, index) {
final type = _topCharacterTypes[index];
final items = state.tops.where((el) => el.type == type).toList();
return ChartCard(
height: _topCardHeight,
width: _topCardWidth,
title: s.translateChartType(type),
//TODO: THIS TEXT
bottom: Text(
'Number of times a character was released',
style: theme.textTheme.caption,
textAlign: TextAlign.center,
),
child: Row(
children: [
Flexible(flex: 70, fit: FlexFit.tight, child: TopPieChart(items: items, colors: _topCharacterColors)),
Flexible(
flex: 30,
fit: FlexFit.tight,
child: ChartLegend(
indicators: items
.mapIndex(
(e, i) => ChartLegendIndicator(
text: e.name,
color: _topCharacterColors[i],
tap: () => CharacterPage.route(e.key, context),
),
)
.toList(),
),
),
],
),
);
},
),
),
Text(s.topWeapons, style: theme.textTheme.headline5),
SizedBox(
height: _topCardBoxHeight,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: _topWeaponTypes.length,
itemBuilder: (ctx, index) {
final type = _topWeaponTypes[index];
final items = state.tops.where((el) => el.type == type).toList();
return ChartCard(
height: _topCardHeight,
width: _topCardWidth,
title: s.translateChartType(type),
bottom: Text(
'Number of times a character was released',
style: theme.textTheme.caption,
textAlign: TextAlign.center,
),
child: Row(
children: [
Flexible(flex: 70, fit: FlexFit.tight, child: TopPieChart(items: items, colors: _topWeaponColors)),
Flexible(
flex: 30,
fit: FlexFit.tight,
child: ChartLegend(
indicators: items
.mapIndex(
(e, i) => ChartLegendIndicator(
text: e.name,
color: _topWeaponColors[i],
tap: () => WeaponPage.route(e.key, context),
),
)
.toList(),
),
),
],
),
);
},
),
),
const SizedBox(height: 10),
Text(s.elements, style: theme.textTheme.headline5),
//TODO: VERSIONS WILL GROW OVER TIME AND THIS CHART MAY LOOK UGLY
ChartCard(
width: mq.size.width,
height: 400,
title: s.mostAndLeastReleased,
bottom: Row(
mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: WrapCrossAlignment.center,
// alignment: WrapAlignment.center,
children: state.elements
.map(
(e) => ChartLegendIndicator(
color: e.type.getElementColorFromContext(context),
text: s.translateElementType(e.type),
expandText: false,
lineThrough: state.selectedElementTypes.contains(e.type),
tap: () => context.read<ChartsBloc>().add(ChartsEvent.elementSelected(type: e.type)),
),
)
.toList(),
),
child: HorizontalBarChart(items: state.filteredElements),
),
Text(s.birthdays, style: theme.textTheme.headline5),
ChartCard(
width: 300,
height: 400,
title: s.mostAndLeastRepeated,
child: VerticalBarChart(items: state.birthdays, months: months),
),
],
);
},
),
),
),
),
),
);
}
}
49 changes: 49 additions & 0 deletions lib/presentation/charts/widgets/chart_card.dart
@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:shiori/presentation/shared/styles.dart';

class ChartCard extends StatelessWidget {
final String title;
final Widget child;
final Widget? bottom;
final double height;
final double width;

const ChartCard({
Key? key,
required this.title,
required this.child,
required this.width,
required this.height,
this.bottom,
}) : super(key: key);

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Card(
shape: Styles.cardShape,
child: Padding(
padding: Styles.edgeInsetAll10,
child: SizedBox(
height: height,
width: width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.only(bottom: 10),
child: Text(
title,
style: theme.textTheme.headline6,
),
),
Expanded(child: child),
if (bottom != null) bottom!,
],
),
),
),
);
}
}
89 changes: 89 additions & 0 deletions lib/presentation/charts/widgets/chart_legend.dart
@@ -0,0 +1,89 @@
import 'package:flutter/material.dart';
import 'package:shiori/presentation/shared/styles.dart';

class ChartLegend extends StatelessWidget {
final List<ChartLegendIndicator> indicators;

const ChartLegend({
Key? key,
required this.indicators,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: indicators,
);
}
}

class ChartLegendIndicator extends StatelessWidget {
final Color color;
final String text;
final double size;
final Function? tap;
final bool expandText;
final bool lineThrough;

const ChartLegendIndicator({
Key? key,
required this.color,
required this.text,
this.size = 16,
this.tap,
this.expandText = true,
this.lineThrough = false,
}) : super(key: key);

@override
Widget build(BuildContext context) {
final textStyle = TextStyle(
fontSize: size,
fontWeight: FontWeight.bold,
color: Colors.grey,
decoration: lineThrough ? TextDecoration.lineThrough : null,
decorationThickness: 3,
);
return Container(
margin: expandText ? const EdgeInsets.symmetric(vertical: 3) : Styles.edgeInsetAll5,
child: InkWell(
onTap: tap != null ? () => tap?.call() : null,
child: Row(
children: [
Container(
width: size,
height: size,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(5),
),
),
const SizedBox(width: 4),
if (expandText)
Expanded(
child: Tooltip(
message: text,
child: Text(
text,
overflow: TextOverflow.ellipsis,
style: textStyle,
),
),
)
else
Tooltip(
message: text,
child: Text(
text,
overflow: TextOverflow.ellipsis,
style: textStyle,
),
)
],
),
),
);
}
}

0 comments on commit 4ebcf24

Please sign in to comment.