diff --git a/lib/ui/widgets/ascension_materials/add_edit_item_bottom_sheet.dart b/lib/ui/widgets/ascension_materials/add_edit_item_bottom_sheet.dart new file mode 100644 index 000000000..4d4fc2e33 --- /dev/null +++ b/lib/ui/widgets/ascension_materials/add_edit_item_bottom_sheet.dart @@ -0,0 +1,144 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:genshindb/common/assets.dart'; + +import '../../../bloc/bloc.dart'; +import '../../../common/extensions/iterable_extensions.dart'; +import '../../../generated/l10n.dart'; +import '../../../models/models.dart'; +import '../common/common_bottom_sheet.dart'; +import '../common/loading.dart'; +import 'skill_item.dart'; + +class AddEditItemBottomSheet extends StatelessWidget { + final int index; + final String keyName; + final bool isInEditMode; + final bool isAWeapon; + + const AddEditItemBottomSheet.toAddItem({ + Key key, + @required this.keyName, + @required this.isAWeapon, + }) : index = null, + isInEditMode = false, + super(key: key); + + const AddEditItemBottomSheet.toEditItem({ + Key key, + @required this.index, + @required this.isAWeapon, + }) : keyName = null, + isInEditMode = true, + super(key: key); + + @override + Widget build(BuildContext context) { + final s = S.of(context); + final theme = Theme.of(context); + return BlocBuilder( + builder: (context, state) => state.map( + loading: (_) => const Loading(), + loaded: (state) => CommonBottomSheet( + title: state.name, + titleIcon: !isInEditMode ? Icons.add : Icons.edit, + iconSize: 40, + onOk: () => Navigator.of(context).pop(true), + onCancel: () => Navigator.of(context).pop(false), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text(s.currentLevel, textAlign: TextAlign.center, style: theme.textTheme.subtitle2), + AscensionLevel(isCurrentLevel: true, level: state.currentLevel), + Container( + margin: const EdgeInsets.only(top: 10), + child: Text(s.desiredLevel, textAlign: TextAlign.center, style: theme.textTheme.subtitle2), + ), + AscensionLevel(isCurrentLevel: false, level: state.desiredLevel), + ...state.skills + .mapIndex((e, index) => SkillItem( + index: index, + name: e.name, + currentLevel: e.currentLevel, + desiredLevel: e.desiredLevel, + )) + .toList() + ], + ), + ), + ), + ); + } + + void _applyChangesForWeapon( + int currentLevel, + int desiredLevel, + BuildContext context, + ) { + if (!isInEditMode) { + context + .read() + .add(CalculatorAscMaterialsEvent.addWeapon(key: keyName, currentLevel: currentLevel, desiredLevel: desiredLevel)); + return; + } + + context + .read() + .add(CalculatorAscMaterialsEvent.updateWeapon(index: 1, currentLevel: currentLevel, desiredLevel: desiredLevel)); + } + + void _applyChangesForCharacter( + int currentLevel, + int desiredLevel, + List skills, + BuildContext context, + ) { + if (!isInEditMode) { + context + .read() + .add(CalculatorAscMaterialsEvent.addCharacter(key: keyName, currentLevel: currentLevel, desiredLevel: desiredLevel, skills: skills)); + } + } +} + +class AscensionLevel extends StatelessWidget { + final bool isCurrentLevel; + final int level; + + const AscensionLevel({ + Key key, + @required this.isCurrentLevel, + @required this.level, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final widgets = []; + + for (var i = CalculatorAscMaterialsItemBloc.minAscensionLevel; i < CalculatorAscMaterialsItemBloc.maxAscensionLevel; i++) { + final isSelected = level > 0 && i <= level; + final button = IconButton( + icon: Opacity( + opacity: isSelected ? 1 : 0.2, + child: Image.asset(Assets.getOtherMaterialPath('mark_wind_crystal.png'), width: 40, height: 40), + ), + onPressed: () { + final bloc = context.read(); + if (isCurrentLevel) { + bloc.add(CalculatorAscMaterialsItemEvent.currentLevelChanged(newValue: i)); + } else { + bloc.add(CalculatorAscMaterialsItemEvent.desiredLevelChanged(newValue: i)); + } + }, + ); + widgets.add(button); + } + + return Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + alignment: WrapAlignment.center, + children: widgets, + ); + } +} diff --git a/lib/ui/widgets/ascension_materials/item_card.dart b/lib/ui/widgets/ascension_materials/item_card.dart new file mode 100644 index 000000000..5e1e0b4cc --- /dev/null +++ b/lib/ui/widgets/ascension_materials/item_card.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:transparent_image/transparent_image.dart'; + +import '../../../bloc/bloc.dart'; +import '../../../common/extensions/rarity_extensions.dart'; +import '../../../common/styles.dart'; +import '../../../generated/l10n.dart'; +import '../../../models/items/item_ascention_material_model.dart'; +import 'add_edit_item_bottom_sheet.dart'; +import 'material_item.dart'; + +class ItemCard extends StatelessWidget { + final int index; + final String itemKey; + final String name; + final String image; + final int rarity; + final bool isWeapon; + final List materials; + + const ItemCard({ + Key key, + @required this.index, + @required this.itemKey, + @required this.name, + @required this.image, + @required this.rarity, + @required this.isWeapon, + @required this.materials, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final s = S.of(context); + return Card( + shape: Styles.mainCardShape, + elevation: Styles.cardTenElevation, + color: rarity + .getRarityColors() + .last, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Stack( + alignment: AlignmentDirectional.bottomEnd, + fit: StackFit.passthrough, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 30), + child: FadeInImage( + height: 340, + placeholder: MemoryImage(kTransparentImage), + image: AssetImage(image), + fit: BoxFit.fill, + ), + ), + Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(35), + bottomRight: Radius.circular(35), + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + color: Colors.black.withOpacity(0.5), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: IconButton( + icon: const Icon(Icons.edit), + color: Colors.white, + onPressed: () => _editItem(context), + ), + ), + Flexible( + child: Tooltip( + message: name, + child: Text( + name, + style: theme.textTheme.headline6.copyWith(color: Colors.white), + overflow: TextOverflow.ellipsis, + ), + ), + ), + Flexible( + child: IconButton( + icon: const Icon(Icons.delete), + color: Colors.white, + onPressed: () => _removeItem(context), + ), + ), + ], + ), + Text( + s.materials, + textAlign: TextAlign.center, + style: theme.textTheme.subtitle2.copyWith(color: Colors.white), + ), + Container( + margin: const EdgeInsets.only(bottom: 10), + child: SizedBox( + height: 70, + child: ListView.builder( + itemCount: materials.length, + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + itemBuilder: (ctx, index) { + final item = materials[index]; + return MaterialItem( + type: item.materialType, + image: item.fullImagePath, + quantity: item.quantity, + ); + }, + ), + ), + ), + ], + ), + ), + ], + ), + ], + ), + ); + } + + void _editItem(BuildContext context) { + final route = MaterialPageRoute(builder: (ctx) => AddEditItemBottomSheet.toEditItem(index: index, isAWeapon: isWeapon)); + Navigator.of(context).push(route); + } + + void _removeItem(BuildContext context) => + context.read().add(CalculatorAscMaterialsEvent.removeItem(index: index)); +} diff --git a/lib/ui/widgets/ascension_materials/material_item.dart b/lib/ui/widgets/ascension_materials/material_item.dart new file mode 100644 index 000000000..96c2efda1 --- /dev/null +++ b/lib/ui/widgets/ascension_materials/material_item.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../../../common/enums/material_type.dart' as app; +import '../../../common/styles.dart'; + +class MaterialItem extends StatelessWidget { + final app.MaterialType type; + final String image; + final int quantity; + + const MaterialItem({ + Key key, + @required this.type, + @required this.image, + @required this.quantity, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Container( + margin: Styles.edgeInsetAll5, + child: Column( + children: [ + Image.asset(image, width: 40, height: 40), + Text( + '$quantity', + textAlign: TextAlign.center, + style: theme.textTheme.subtitle2.copyWith(color: Colors.white), + ), + ], + ), + ); + } +} diff --git a/lib/ui/widgets/ascension_materials/skill_item.dart b/lib/ui/widgets/ascension_materials/skill_item.dart new file mode 100644 index 000000000..c71dc7fcb --- /dev/null +++ b/lib/ui/widgets/ascension_materials/skill_item.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + + +import '../../../bloc/bloc.dart'; +import '../../../common/styles.dart'; +import '../../../generated/l10n.dart'; +import '../common/increment_button.dart'; + +class SkillItem extends StatelessWidget { + final int index; + final String name; + final int currentLevel; + final int desiredLevel; + + const SkillItem({ + Key key, + @required this.index, + @required this.name, + @required this.currentLevel, + @required this.desiredLevel, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final s = S.of(context); + + return Container( + margin: Styles.edgeInsetVertical5, + padding: Styles.edgeInsetHorizontal16, + child: Column( + children: [ + Text(name, style: theme.textTheme.subtitle2), + const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + IncrementButton( + title: s.currentLevel, + value: currentLevel, + incrementIsDisabled: currentLevel == CalculatorAscMaterialsItemBloc.maxSkillLevel, + decrementIsDisabled: currentLevel == CalculatorAscMaterialsItemBloc.minSkillLevel, + onMinus: (val) { + context + .read() + .add(CalculatorAscMaterialsItemEvent.skillCurrentLevelChanged(index: index, newValue: val)); + }, + onAdd: (val) { + context + .read() + .add(CalculatorAscMaterialsItemEvent.skillCurrentLevelChanged(index: index, newValue: val)); + }, + ), + IncrementButton( + title: s.desiredLevel, + value: desiredLevel, + incrementIsDisabled: desiredLevel == CalculatorAscMaterialsItemBloc.maxSkillLevel, + decrementIsDisabled: desiredLevel == CalculatorAscMaterialsItemBloc.minSkillLevel, + onMinus: (val) { + context + .read() + .add(CalculatorAscMaterialsItemEvent.skillDesiredLevelChanged(index: index, newValue: val)); + }, + onAdd: (val) { + context + .read() + .add(CalculatorAscMaterialsItemEvent.skillDesiredLevelChanged(index: index, newValue: val)); + }, + ), + ], + ), + ], + ), + ); + } +}