mirror of
https://github.com/DungeonPaper/dungeon-paper-app.git
synced 2026-05-17 17:58:11 +00:00
feat: home cards list view
This commit is contained in:
@@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
|
||||
|
||||
enum RacePosition { start, end }
|
||||
|
||||
enum FavoritesView { cards, list }
|
||||
|
||||
@immutable
|
||||
class CharacterSettings {
|
||||
const CharacterSettings({
|
||||
@@ -17,6 +19,7 @@ class CharacterSettings {
|
||||
this.racePosition = RacePosition.start,
|
||||
this.lightTheme,
|
||||
this.darkTheme,
|
||||
this.favoritesView = FavoritesView.cards,
|
||||
});
|
||||
|
||||
final NoteCategoryList noteCategories;
|
||||
@@ -29,6 +32,7 @@ class CharacterSettings {
|
||||
final RacePosition racePosition;
|
||||
final int? lightTheme;
|
||||
final int? darkTheme;
|
||||
final FavoritesView favoritesView;
|
||||
|
||||
CharacterSettings copyWith({
|
||||
int? sortOrder,
|
||||
@@ -40,18 +44,19 @@ class CharacterSettings {
|
||||
RacePosition? racePosition,
|
||||
int? lightTheme,
|
||||
int? darkTheme,
|
||||
}) =>
|
||||
CharacterSettings(
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
category: category ?? this.category,
|
||||
rollButtons: rollButtons ?? this.rollButtons,
|
||||
actionCategories: actionCategories ?? this.actionCategories,
|
||||
noteCategories: noteCategories ?? this.noteCategories,
|
||||
racePosition: racePosition ?? this.racePosition,
|
||||
quickCategories: quickCategories ?? this.quickCategories,
|
||||
lightTheme: lightTheme ?? this.lightTheme,
|
||||
darkTheme: darkTheme ?? this.darkTheme,
|
||||
);
|
||||
FavoritesView? favoritesView,
|
||||
}) => CharacterSettings(
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
category: category ?? this.category,
|
||||
rollButtons: rollButtons ?? this.rollButtons,
|
||||
actionCategories: actionCategories ?? this.actionCategories,
|
||||
noteCategories: noteCategories ?? this.noteCategories,
|
||||
racePosition: racePosition ?? this.racePosition,
|
||||
quickCategories: quickCategories ?? this.quickCategories,
|
||||
lightTheme: lightTheme ?? this.lightTheme,
|
||||
darkTheme: darkTheme ?? this.darkTheme,
|
||||
favoritesView: favoritesView ?? this.favoritesView,
|
||||
);
|
||||
|
||||
factory CharacterSettings.fromRawJson(String str) =>
|
||||
CharacterSettings.fromJson(json.decode(str));
|
||||
@@ -60,57 +65,56 @@ class CharacterSettings {
|
||||
|
||||
factory CharacterSettings.fromJson(Map<String, dynamic> json) =>
|
||||
CharacterSettings(
|
||||
noteCategories: json['noteCategories'] != null
|
||||
? NoteCategoryList.fromJson(json['noteCategories'])
|
||||
: const NoteCategoryList(sortOrder: {}),
|
||||
actionCategories: json['actionCategories'] != null
|
||||
? ActionCategoryList.fromJson(json['actionCategories'])
|
||||
: const ActionCategoryList(
|
||||
sortOrder: {},
|
||||
hidden: {},
|
||||
),
|
||||
quickCategories: json['actionCategories'] != null
|
||||
? ActionCategoryList.fromJson(json['actionCategories'])
|
||||
: const ActionCategoryList(
|
||||
sortOrder: {},
|
||||
hidden: {},
|
||||
),
|
||||
noteCategories:
|
||||
json['noteCategories'] != null
|
||||
? NoteCategoryList.fromJson(json['noteCategories'])
|
||||
: const NoteCategoryList(sortOrder: {}),
|
||||
actionCategories:
|
||||
json['actionCategories'] != null
|
||||
? ActionCategoryList.fromJson(json['actionCategories'])
|
||||
: const ActionCategoryList(sortOrder: {}, hidden: {}),
|
||||
quickCategories:
|
||||
json['actionCategories'] != null
|
||||
? ActionCategoryList.fromJson(json['actionCategories'])
|
||||
: const ActionCategoryList(sortOrder: {}, hidden: {}),
|
||||
sortOrder: json['sortOrder'],
|
||||
category: json['category'],
|
||||
rollButtons: List<RollButton?>.from((json['rollButtons'] ?? [])
|
||||
.map((x) => x != null ? RollButton.fromJson(x) : null)),
|
||||
rollButtons: List<RollButton?>.from(
|
||||
(json['rollButtons'] ?? []).map(
|
||||
(x) => x != null ? RollButton.fromJson(x) : null,
|
||||
),
|
||||
),
|
||||
racePosition: RacePosition.values.firstWhere(
|
||||
(element) => element.name == json['racePosition'],
|
||||
orElse: () => RacePosition.start,
|
||||
),
|
||||
lightTheme: json['lightTheme'],
|
||||
darkTheme: json['darkTheme'],
|
||||
favoritesView: FavoritesView.values.firstWhere(
|
||||
(element) => element.name == json['favoritesView'],
|
||||
orElse: () => FavoritesView.cards,
|
||||
),
|
||||
);
|
||||
|
||||
factory CharacterSettings.empty() => const CharacterSettings(
|
||||
rollButtons: [],
|
||||
noteCategories: NoteCategoryList(sortOrder: {}),
|
||||
actionCategories: ActionCategoryList(
|
||||
sortOrder: {},
|
||||
hidden: {},
|
||||
),
|
||||
quickCategories: ActionCategoryList(
|
||||
sortOrder: {},
|
||||
hidden: {},
|
||||
),
|
||||
);
|
||||
rollButtons: [],
|
||||
noteCategories: NoteCategoryList(sortOrder: {}),
|
||||
actionCategories: ActionCategoryList(sortOrder: {}, hidden: {}),
|
||||
quickCategories: ActionCategoryList(sortOrder: {}, hidden: {}),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'sortOrder': sortOrder,
|
||||
'category': category,
|
||||
'rollButtons': List<dynamic>.from(rollButtons.map((x) => x?.toJson())),
|
||||
'noteCategories': noteCategories.toJson(),
|
||||
'actionCategories': actionCategories.toJson(),
|
||||
'quickCategories': quickCategories.toJson(),
|
||||
'racePosition': racePosition.name,
|
||||
'lightTheme': lightTheme,
|
||||
'darkTheme': darkTheme,
|
||||
};
|
||||
'sortOrder': sortOrder,
|
||||
'category': category,
|
||||
'rollButtons': List<dynamic>.from(rollButtons.map((x) => x?.toJson())),
|
||||
'noteCategories': noteCategories.toJson(),
|
||||
'actionCategories': actionCategories.toJson(),
|
||||
'quickCategories': quickCategories.toJson(),
|
||||
'racePosition': racePosition.name,
|
||||
'lightTheme': lightTheme,
|
||||
'darkTheme': darkTheme,
|
||||
'favoritesView': favoritesView.name,
|
||||
};
|
||||
|
||||
CharacterSettings copyWithThemes({int? lightTheme, int? darkTheme}) =>
|
||||
CharacterSettings(
|
||||
@@ -123,10 +127,11 @@ class CharacterSettings {
|
||||
noteCategories: noteCategories,
|
||||
racePosition: racePosition,
|
||||
quickCategories: quickCategories,
|
||||
favoritesView: favoritesView,
|
||||
);
|
||||
|
||||
String get debugProperties =>
|
||||
'sortOrder: $sortOrder, category: $category, rollButtons: $rollButtons, noteCategories: $noteCategories, actionCategories: $actionCategories, quickCategories: $quickCategories, racePosition: $racePosition, lightTheme: $lightTheme, darkTheme: $darkTheme';
|
||||
'sortOrder: $sortOrder, category: $category, rollButtons: $rollButtons, noteCategories: $noteCategories, actionCategories: $actionCategories, quickCategories: $quickCategories, racePosition: $racePosition, lightTheme: $lightTheme, darkTheme: $darkTheme, favoritesView: $favoritesView';
|
||||
|
||||
@override
|
||||
String toString() => 'CharacterSettings($debugProperties)';
|
||||
@@ -144,20 +149,22 @@ class CharacterSettings {
|
||||
quickCategories == other.quickCategories &&
|
||||
racePosition == other.racePosition &&
|
||||
lightTheme == other.lightTheme &&
|
||||
darkTheme == other.darkTheme;
|
||||
darkTheme == other.darkTheme &&
|
||||
favoritesView == other.favoritesView;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll([
|
||||
sortOrder,
|
||||
category,
|
||||
rollButtons,
|
||||
noteCategories,
|
||||
actionCategories,
|
||||
quickCategories,
|
||||
racePosition,
|
||||
lightTheme,
|
||||
darkTheme,
|
||||
]);
|
||||
sortOrder,
|
||||
category,
|
||||
rollButtons,
|
||||
noteCategories,
|
||||
actionCategories,
|
||||
quickCategories,
|
||||
racePosition,
|
||||
lightTheme,
|
||||
darkTheme,
|
||||
favoritesView,
|
||||
]);
|
||||
}
|
||||
|
||||
@immutable
|
||||
@@ -175,11 +182,11 @@ class OrderedCategoryList<T> {
|
||||
final bool canHide;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
// 'categories': List<dynamic>.from(categories),
|
||||
'hidden': List<dynamic>.from(hidden),
|
||||
'sortOrder': List<dynamic>.from(sortOrder),
|
||||
'canHide': canHide,
|
||||
};
|
||||
// 'categories': List<dynamic>.from(categories),
|
||||
'hidden': List<dynamic>.from(hidden),
|
||||
'sortOrder': List<dynamic>.from(sortOrder),
|
||||
'canHide': canHide,
|
||||
};
|
||||
|
||||
factory OrderedCategoryList.fromRawJson(String str) =>
|
||||
OrderedCategoryList.fromJson(json.decode(str));
|
||||
@@ -196,23 +203,18 @@ class OrderedCategoryList<T> {
|
||||
Set<String>? hidden,
|
||||
Set<String>? sortOrder,
|
||||
bool? canHide,
|
||||
}) =>
|
||||
OrderedCategoryList(
|
||||
hidden: hidden ?? this.hidden,
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
canHide: canHide ?? this.canHide,
|
||||
);
|
||||
}) => OrderedCategoryList(
|
||||
hidden: hidden ?? this.hidden,
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
canHide: canHide ?? this.canHide,
|
||||
);
|
||||
|
||||
Set<T> getSorted([Set<T> all = const {}]) => <T>{
|
||||
Set<T> getSorted([Set<T> all = const {}]) =>
|
||||
<T>{
|
||||
...sortOrder,
|
||||
...all,
|
||||
// .toList()..sort(stringSorter(order: SortOrder.asc))
|
||||
}
|
||||
.where(
|
||||
(cat) => !hidden.contains(cat),
|
||||
)
|
||||
.toSet()
|
||||
.cast<T>();
|
||||
}.where((cat) => !hidden.contains(cat)).toSet().cast<T>();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
@@ -224,11 +226,7 @@ class OrderedCategoryList<T> {
|
||||
canHide == other.canHide;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll([
|
||||
hidden,
|
||||
sortOrder,
|
||||
canHide,
|
||||
]);
|
||||
int get hashCode => Object.hashAll([hidden, sortOrder, canHide]);
|
||||
|
||||
String get debugProperties =>
|
||||
'hidden: $hidden, sortOrder: $sortOrder, canHide: $canHide';
|
||||
@@ -248,17 +246,12 @@ class NoteCategoryList extends OrderedCategoryList<String> {
|
||||
NoteCategoryList.fromJson(json.decode(str));
|
||||
|
||||
factory NoteCategoryList.fromJson(Map<String, dynamic> json) =>
|
||||
NoteCategoryList(
|
||||
sortOrder: Set<String>.from(json['sortOrder']),
|
||||
);
|
||||
NoteCategoryList(sortOrder: Set<String>.from(json['sortOrder']));
|
||||
|
||||
NoteCategoryList copyWithInherited({
|
||||
// Set<String>? categories,
|
||||
Set<String>? sortOrder,
|
||||
}) =>
|
||||
NoteCategoryList(
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
);
|
||||
}) => NoteCategoryList(sortOrder: sortOrder ?? this.sortOrder);
|
||||
|
||||
@override
|
||||
String get debugProperties => 'sortOrder: $sortOrder';
|
||||
@@ -288,11 +281,10 @@ class ActionCategoryList extends OrderedCategoryList<String> {
|
||||
// Set<String>? categories,
|
||||
Set<String>? sortOrder,
|
||||
Set<String>? hidden,
|
||||
}) =>
|
||||
ActionCategoryList(
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
hidden: hidden ?? this.hidden,
|
||||
);
|
||||
}) => ActionCategoryList(
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
hidden: hidden ?? this.hidden,
|
||||
);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:dungeon_paper/app/data/models/character_settings.dart';
|
||||
import 'package:dungeon_paper/app/data/models/item.dart';
|
||||
import 'package:dungeon_paper/app/data/models/meta.dart';
|
||||
import 'package:dungeon_paper/app/data/models/move.dart';
|
||||
@@ -25,6 +26,7 @@ import 'package:dungeon_paper/app/widgets/cards/spell_card.dart';
|
||||
import 'package:dungeon_paper/app/widgets/cards/spell_card_mini.dart';
|
||||
import 'package:dungeon_paper/app/widgets/dialogs/confirm_delete_dialog.dart';
|
||||
import 'package:dungeon_paper/app/widgets/menus/entity_edit_menu.dart';
|
||||
import 'package:dungeon_paper/core/utils/list_utils.dart';
|
||||
import 'package:dungeon_paper/i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -58,14 +60,14 @@ class HomeCharacterDynamicCards extends StatelessWidget
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
...{...controller.current.actionCategories, 'Note'}
|
||||
.map((cat) => _buildList(context, controller, cat))
|
||||
.map((cat) => _buildListByType(context, controller, cat))
|
||||
.reduce((value, element) => value + element),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildList(
|
||||
List<Widget> _buildListByType(
|
||||
BuildContext context,
|
||||
CharacterProvider controller,
|
||||
String cat,
|
||||
@@ -169,8 +171,9 @@ class HomeCharacterDynamicCards extends StatelessWidget
|
||||
|
||||
List<Widget> classActionCards(
|
||||
BuildContext context,
|
||||
CharacterProvider charProvider,
|
||||
) {
|
||||
CharacterProvider charProvider, {
|
||||
required bool expandable,
|
||||
}) {
|
||||
final raceCard = RaceCard(
|
||||
race: char.race,
|
||||
onSave:
|
||||
@@ -194,6 +197,8 @@ class HomeCharacterDynamicCards extends StatelessWidget
|
||||
);
|
||||
final alignmentCard = AlignmentValueCard(
|
||||
alignment: char.bio.alignment,
|
||||
expandable: expandable,
|
||||
initiallyExpanded: !expandable,
|
||||
actions: [
|
||||
EntityEditMenu(
|
||||
onDelete: null,
|
||||
@@ -225,376 +230,373 @@ class HomeCharacterDynamicCards extends StatelessWidget
|
||||
}, T);
|
||||
}
|
||||
|
||||
List<Widget> _notesList(BuildContext context, CharacterProvider controller) {
|
||||
List<Widget> _listViewBuilder<T extends WithMeta>(
|
||||
BuildContext context,
|
||||
CharacterProvider controller, {
|
||||
required List<T> list,
|
||||
required Widget Function(BuildContext, LibraryProvider, T) cardBuilder,
|
||||
required Widget Function(BuildContext, LibraryProvider, T, VoidCallback)
|
||||
cardMiniBuilder,
|
||||
required Widget Function(BuildContext, LibraryProvider, T)
|
||||
expandedCardBuilder,
|
||||
required String title,
|
||||
}) {
|
||||
if (list.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
if (notes.isNotEmpty) ...[
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(tr.home.categories.notes),
|
||||
),
|
||||
],
|
||||
HorizontalCardListView<Note>(
|
||||
cardSize: cardSize,
|
||||
items: notes,
|
||||
cardBuilder:
|
||||
(context, note, index, onTap) => NoteCardMini(
|
||||
note: notes[index],
|
||||
onTap: onTap,
|
||||
onSave:
|
||||
(note) => controller.updateCharacter(
|
||||
CharacterUtils.updateNotes(controller.current, [note]),
|
||||
),
|
||||
),
|
||||
expandedCardBuilder:
|
||||
(context, note, index) =>
|
||||
notes.isNotEmpty && index < notes.length
|
||||
? NoteCard(
|
||||
maxContentHeight: maxContentHeight(context),
|
||||
expandable: false,
|
||||
initiallyExpanded: true,
|
||||
note: notes[index],
|
||||
actions: [
|
||||
EntityEditMenu(
|
||||
onEdit:
|
||||
() => ModelPages.openNotePage(
|
||||
context,
|
||||
note: notes[index],
|
||||
onSave:
|
||||
(note) => controller.updateCharacter(
|
||||
CharacterUtils.updateNotes(
|
||||
controller.current,
|
||||
[note],
|
||||
),
|
||||
),
|
||||
),
|
||||
onDelete: _delete(
|
||||
context,
|
||||
note,
|
||||
note.title,
|
||||
tn(Note),
|
||||
() => controller.updateCharacter(
|
||||
CharacterUtils.removeNotes(controller.current, [
|
||||
note,
|
||||
]),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onSave: (note) {
|
||||
controller.updateCharacter(
|
||||
CharacterUtils.updateNotes(controller.current, [
|
||||
note,
|
||||
]),
|
||||
);
|
||||
if (!note.favorite) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16).copyWith(top: 10),
|
||||
child: Text(title),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _movesList(BuildContext context, CharacterProvider controller) {
|
||||
return [
|
||||
if (moves.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(tr.home.categories.moves),
|
||||
),
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return HorizontalCardListView<Move>(
|
||||
if (char.settings.favoritesView == FavoritesView.list) {
|
||||
return Column(
|
||||
children: [
|
||||
for (final item in list)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8, left: 8, right: 8),
|
||||
child: LibraryProvider.consumer(
|
||||
(context, library, _) =>
|
||||
cardBuilder(context, library, item),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return HorizontalCardListView<T>(
|
||||
cardSize: cardSize,
|
||||
items: moves,
|
||||
items: list,
|
||||
cardBuilder:
|
||||
(context, move, index, onTap) => MoveCardMini(
|
||||
move: moves[index],
|
||||
onTap: onTap,
|
||||
onSave:
|
||||
(move) => controller.updateCharacter(
|
||||
CharacterUtils.updateMoves(controller.current, [move]),
|
||||
),
|
||||
abilityScores: controller.current.abilityScores,
|
||||
(context, item, index, onTap) => LibraryProvider.consumer(
|
||||
(context, library, _) =>
|
||||
cardMiniBuilder(context, library, item, onTap),
|
||||
),
|
||||
expandedCardBuilder:
|
||||
(context, move, index) =>
|
||||
LibraryProvider.consumer((context, library, _) {
|
||||
return moves.isNotEmpty && index < moves.length
|
||||
? MoveCard(
|
||||
maxContentHeight: maxContentHeight(context),
|
||||
expandable: false,
|
||||
initiallyExpanded: true,
|
||||
move: moves[index],
|
||||
abilityScores: controller.current.abilityScores,
|
||||
actions: [
|
||||
EntityEditMenu(
|
||||
onEdit:
|
||||
() => ModelPages.openMovePage(
|
||||
context,
|
||||
abilityScores:
|
||||
controller.current.abilityScores,
|
||||
move: moves[index],
|
||||
onSave:
|
||||
(move) => library.upsertToCharacter(
|
||||
[move],
|
||||
forkBehavior:
|
||||
ForkBehavior.increaseVersion,
|
||||
),
|
||||
),
|
||||
onDelete: _delete(
|
||||
context,
|
||||
move,
|
||||
move.name,
|
||||
tn(Move),
|
||||
() => controller.updateCharacter(
|
||||
CharacterUtils.removeMoves(
|
||||
controller.current,
|
||||
[move],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onSave: (move) {
|
||||
controller.updateCharacter(
|
||||
CharacterUtils.updateMoves(controller.current, [
|
||||
move,
|
||||
]),
|
||||
);
|
||||
if (!move.favorite) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
}),
|
||||
// leading: raceCardMini != null &&
|
||||
// controller.current.settings.racePosition ==
|
||||
// RacePosition.start
|
||||
// ? [raceCardMini]
|
||||
// : [],
|
||||
// trailing: raceCardMini != null &&
|
||||
// controller.current.settings.racePosition ==
|
||||
// RacePosition.end
|
||||
// ? [raceCardMini]
|
||||
// : [],
|
||||
(context, item, index) => LibraryProvider.consumer(
|
||||
(context, library, _) =>
|
||||
list.isNotEmpty && index < list.length
|
||||
? expandedCardBuilder(context, library, item)
|
||||
: SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _spellsList(BuildContext context, CharacterProvider controller) {
|
||||
return [
|
||||
if (spells.isNotEmpty) ...[
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(tr.home.categories.spells),
|
||||
List<Widget> _notesList(BuildContext context, CharacterProvider controller) {
|
||||
onSave(Note note) => controller.updateCharacter(
|
||||
CharacterUtils.updateNotes(controller.current, [note]),
|
||||
);
|
||||
actions(LibraryProvider library, Note note) => [
|
||||
EntityEditMenu(
|
||||
onEdit:
|
||||
() => ModelPages.openNotePage(context, note: note, onSave: onSave),
|
||||
onDelete: _delete(
|
||||
context,
|
||||
note,
|
||||
note.title,
|
||||
tn(Note),
|
||||
() => controller.updateCharacter(
|
||||
CharacterUtils.removeNotes(controller.current, [note]),
|
||||
),
|
||||
),
|
||||
],
|
||||
HorizontalCardListView<Spell>(
|
||||
cardSize: cardSize,
|
||||
items: spells,
|
||||
cardBuilder:
|
||||
(context, spell, index, onTap) => SpellCardMini(
|
||||
spell: spells[index],
|
||||
onTap: onTap,
|
||||
onSave:
|
||||
(spell) => controller.updateCharacter(
|
||||
CharacterUtils.updateSpells(controller.current, [spell]),
|
||||
),
|
||||
abilityScores: controller.current.abilityScores,
|
||||
),
|
||||
expandedCardBuilder:
|
||||
(context, spell, index) =>
|
||||
spells.isNotEmpty && index < spells.length
|
||||
? SpellCard(
|
||||
maxContentHeight: maxContentHeight(context),
|
||||
expandable: false,
|
||||
initiallyExpanded: true,
|
||||
spell: spells[index],
|
||||
abilityScores: controller.current.abilityScores,
|
||||
actions: [
|
||||
EntityEditMenu(
|
||||
onEdit:
|
||||
() => ModelPages.openSpellPage(
|
||||
context,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
classKeys: spells[index].classKeys,
|
||||
spell: spells[index],
|
||||
onSave:
|
||||
(spell) => controller.updateCharacter(
|
||||
CharacterUtils.updateSpells(
|
||||
controller.current,
|
||||
[spell],
|
||||
),
|
||||
),
|
||||
),
|
||||
onDelete: _delete(
|
||||
context,
|
||||
spell,
|
||||
spell.name,
|
||||
tn(Spell),
|
||||
() => controller.updateCharacter(
|
||||
CharacterUtils.removeSpells(controller.current, [
|
||||
spell,
|
||||
]),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onSave: (spell) {
|
||||
controller.updateCharacter(
|
||||
CharacterUtils.updateSpells(controller.current, [
|
||||
spell,
|
||||
]),
|
||||
);
|
||||
if (!spell.prepared) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
];
|
||||
|
||||
return _listViewBuilder<Note>(
|
||||
context,
|
||||
controller,
|
||||
title: tr.home.categories.notes,
|
||||
list: notes,
|
||||
cardMiniBuilder:
|
||||
(context, library, note, onTap) =>
|
||||
NoteCardMini(note: note, onTap: onTap, onSave: onSave),
|
||||
cardBuilder:
|
||||
(context, library, note) => NoteCard(
|
||||
note: note,
|
||||
onSave: onSave,
|
||||
actions: actions(library, note),
|
||||
),
|
||||
expandedCardBuilder:
|
||||
(context, library, note) => NoteCard(
|
||||
maxContentHeight: maxContentHeight(context),
|
||||
expandable: false,
|
||||
initiallyExpanded: true,
|
||||
note: note,
|
||||
actions: actions(library, note),
|
||||
onSave: (note) {
|
||||
onSave(note);
|
||||
if (!note.favorite) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _movesList(BuildContext context, CharacterProvider controller) {
|
||||
onSave(Move move) => controller.updateCharacter(
|
||||
CharacterUtils.updateMoves(controller.current, [move]),
|
||||
);
|
||||
actions(LibraryProvider library, Move move) => [
|
||||
EntityEditMenu(
|
||||
onEdit:
|
||||
() => ModelPages.openMovePage(
|
||||
context,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
move: move,
|
||||
onSave: onSave,
|
||||
),
|
||||
onDelete: _delete(
|
||||
context,
|
||||
move,
|
||||
move.name,
|
||||
tn(Move),
|
||||
() => controller.updateCharacter(
|
||||
CharacterUtils.removeMoves(controller.current, [move]),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
return _listViewBuilder<Move>(
|
||||
context,
|
||||
controller,
|
||||
title: tr.home.categories.moves,
|
||||
list: moves,
|
||||
cardMiniBuilder:
|
||||
(context, library, move, onTap) => MoveCardMini(
|
||||
move: move,
|
||||
onTap: onTap,
|
||||
onSave: onSave,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
),
|
||||
cardBuilder:
|
||||
(context, library, move) => MoveCard(
|
||||
move: move,
|
||||
onSave: onSave,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
actions: actions(library, move),
|
||||
),
|
||||
expandedCardBuilder:
|
||||
(context, library, move) => MoveCard(
|
||||
maxContentHeight: maxContentHeight(context),
|
||||
expandable: false,
|
||||
initiallyExpanded: true,
|
||||
move: move,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
actions: actions(library, move),
|
||||
onSave: (move) {
|
||||
controller.updateCharacter(
|
||||
CharacterUtils.updateMoves(controller.current, [move]),
|
||||
);
|
||||
if (!move.favorite) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _spellsList(BuildContext context, CharacterProvider controller) {
|
||||
onSave(Spell spell) => controller.updateCharacter(
|
||||
CharacterUtils.updateSpells(controller.current, [spell]),
|
||||
);
|
||||
actions(LibraryProvider library, Spell spell) => [
|
||||
EntityEditMenu(
|
||||
onEdit:
|
||||
() => ModelPages.openSpellPage(
|
||||
context,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
classKeys: spell.classKeys,
|
||||
spell: spell,
|
||||
onSave: onSave,
|
||||
),
|
||||
onDelete: _delete(
|
||||
context,
|
||||
spell,
|
||||
spell.name,
|
||||
tn(Spell),
|
||||
() => controller.updateCharacter(
|
||||
CharacterUtils.removeSpells(controller.current, [spell]),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
return _listViewBuilder<Spell>(
|
||||
context,
|
||||
controller,
|
||||
title: tr.home.categories.spells,
|
||||
list: spells,
|
||||
cardMiniBuilder:
|
||||
(context, library, spell, onTap) => SpellCardMini(
|
||||
spell: spell,
|
||||
onTap: onTap,
|
||||
onSave: onSave,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
),
|
||||
cardBuilder:
|
||||
(context, library, spell) => SpellCard(
|
||||
spell: spell,
|
||||
onSave: onSave,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
actions: actions(library, spell),
|
||||
),
|
||||
expandedCardBuilder:
|
||||
(context, library, spell) => SpellCard(
|
||||
maxContentHeight: maxContentHeight(context),
|
||||
expandable: false,
|
||||
initiallyExpanded: true,
|
||||
spell: spell,
|
||||
abilityScores: controller.current.abilityScores,
|
||||
actions: actions(library, spell),
|
||||
onSave: (spell) {
|
||||
onSave(spell);
|
||||
if (!spell.prepared) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _itemsList(BuildContext context, CharacterProvider controller) {
|
||||
return [
|
||||
if (items.isNotEmpty) ...[
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(tr.home.categories.items),
|
||||
),
|
||||
],
|
||||
HorizontalCardListView<Item>(
|
||||
cardSize: cardSize,
|
||||
items: items,
|
||||
cardBuilder:
|
||||
(context, item, index, onTap) => ItemCardMini(
|
||||
item: items[index],
|
||||
onTap: onTap,
|
||||
onSave(Item item) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(controller.current, [item]),
|
||||
);
|
||||
|
||||
actions(LibraryProvider library, Item item) => [
|
||||
EntityEditMenu(
|
||||
onEdit:
|
||||
() => ModelPages.openItemPage(
|
||||
context,
|
||||
item: item,
|
||||
onSave:
|
||||
(item) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(controller.current, [item]),
|
||||
),
|
||||
(item) => library.upsertToCharacter([
|
||||
item,
|
||||
], forkBehavior: ForkBehavior.increaseVersion),
|
||||
),
|
||||
expandedCardBuilder:
|
||||
(context, item, index) =>
|
||||
items.isNotEmpty && index < items.length
|
||||
? ItemCard(
|
||||
maxContentHeight: maxContentHeight(context),
|
||||
expandable: false,
|
||||
initiallyExpanded: true,
|
||||
item: items[index],
|
||||
actions: [
|
||||
EntityEditMenu(
|
||||
onEdit:
|
||||
() => ModelPages.openItemPage(
|
||||
context,
|
||||
item: items[index],
|
||||
onSave:
|
||||
(item) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(
|
||||
controller.current,
|
||||
[item],
|
||||
),
|
||||
),
|
||||
),
|
||||
onDelete: _delete(
|
||||
context,
|
||||
item,
|
||||
item.name,
|
||||
tn(Item),
|
||||
() => controller.updateCharacter(
|
||||
CharacterUtils.removeItems(controller.current, [
|
||||
item,
|
||||
]),
|
||||
),
|
||||
),
|
||||
leading: [
|
||||
ChecklistMenuEntry(
|
||||
value: 'countArmor',
|
||||
checked: item.settings.countArmor,
|
||||
label: Text(tr.items.settings.countArmor),
|
||||
onChanged:
|
||||
(value) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(
|
||||
controller.current,
|
||||
[
|
||||
item.copyWithInherited(
|
||||
settings: item.settings.copyWith(
|
||||
countArmor: value!,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
ChecklistMenuEntry(
|
||||
value: 'countDamage',
|
||||
checked: item.settings.countDamage,
|
||||
label: Text(tr.items.settings.countDamage),
|
||||
onChanged:
|
||||
(value) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(
|
||||
controller.current,
|
||||
[
|
||||
item.copyWithInherited(
|
||||
settings: item.settings.copyWith(
|
||||
countDamage: value!,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
ChecklistMenuEntry(
|
||||
value: 'countWeight',
|
||||
checked: item.settings.countWeight,
|
||||
label: Text(tr.items.settings.countWeight),
|
||||
onChanged:
|
||||
(value) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(
|
||||
controller.current,
|
||||
[
|
||||
item.copyWithInherited(
|
||||
settings: item.settings.copyWith(
|
||||
countWeight: value!,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
onSave: (item) {
|
||||
controller.updateCharacter(
|
||||
CharacterUtils.updateItems(controller.current, [
|
||||
item,
|
||||
]),
|
||||
);
|
||||
if (!item.equipped) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
onDelete: _delete(
|
||||
context,
|
||||
item,
|
||||
item.name,
|
||||
tn(Item),
|
||||
() => controller.updateCharacter(
|
||||
CharacterUtils.removeItems(controller.current, [item]),
|
||||
),
|
||||
),
|
||||
leading: [
|
||||
ChecklistMenuEntry(
|
||||
value: 'countArmor',
|
||||
checked: item.settings.countArmor,
|
||||
label: Text(tr.items.settings.countArmor),
|
||||
onChanged:
|
||||
(value) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(controller.current, [
|
||||
item.copyWithInherited(
|
||||
settings: item.settings.copyWith(countArmor: value!),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
ChecklistMenuEntry(
|
||||
value: 'countDamage',
|
||||
checked: item.settings.countDamage,
|
||||
label: Text(tr.items.settings.countDamage),
|
||||
onChanged:
|
||||
(value) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(controller.current, [
|
||||
item.copyWithInherited(
|
||||
settings: item.settings.copyWith(countDamage: value!),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
ChecklistMenuEntry(
|
||||
value: 'countWeight',
|
||||
checked: item.settings.countWeight,
|
||||
label: Text(tr.items.settings.countWeight),
|
||||
onChanged:
|
||||
(value) => controller.updateCharacter(
|
||||
CharacterUtils.updateItems(controller.current, [
|
||||
item.copyWithInherited(
|
||||
settings: item.settings.copyWith(countWeight: value!),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
return _listViewBuilder<Item>(
|
||||
context,
|
||||
controller,
|
||||
title: tr.home.categories.items,
|
||||
list: items,
|
||||
cardMiniBuilder:
|
||||
(context, library, item, onTap) =>
|
||||
ItemCardMini(item: item, onTap: onTap, onSave: onSave),
|
||||
cardBuilder:
|
||||
(context, library, item) => ItemCard(
|
||||
item: item,
|
||||
onSave: onSave,
|
||||
actions: actions(library, item),
|
||||
),
|
||||
expandedCardBuilder:
|
||||
(context, library, item) => ItemCard(
|
||||
maxContentHeight: maxContentHeight(context),
|
||||
expandable: false,
|
||||
initiallyExpanded: true,
|
||||
item: item,
|
||||
actions: actions(library, item),
|
||||
onSave: (item) {
|
||||
controller.updateCharacter(
|
||||
CharacterUtils.updateItems(controller.current, [item]),
|
||||
);
|
||||
if (!item.equipped) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _classActionsList(
|
||||
BuildContext context,
|
||||
CharacterProvider controller,
|
||||
) {
|
||||
if (controller.current.classActions.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
if (controller.current.settings.favoritesView == FavoritesView.list) {
|
||||
return [
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(tr.home.categories.classActions),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
for (final item in enumerate(classActions))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8, left: 8, right: 8),
|
||||
child: LibraryProvider.consumer(
|
||||
(context, library, _) =>
|
||||
classActionCards(
|
||||
context,
|
||||
controller,
|
||||
expandable: true,
|
||||
)[item.index],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
@@ -609,7 +611,7 @@ class HomeCharacterDynamicCards extends StatelessWidget
|
||||
classActionCardsMini(context, controller)[index],
|
||||
expandedCardBuilder:
|
||||
(context, item, index) =>
|
||||
classActionCards(context, controller)[index],
|
||||
classActionCards(context, controller, expandable: false)[index],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:dungeon_paper/app/routes/app_pages.dart';
|
||||
import 'package:dungeon_paper/app/widgets/atoms/menu_button.dart';
|
||||
import 'package:dungeon_paper/app/widgets/dialogs/character_bio_dialog.dart';
|
||||
import 'package:dungeon_paper/app/widgets/dialogs/character_bonds_flags_dialog.dart';
|
||||
import 'package:dungeon_paper/app/widgets/dialogs/character_favorites_view_select_dialog.dart';
|
||||
import 'package:dungeon_paper/app/widgets/dialogs/custom_roll_buttons_dialog.dart';
|
||||
import 'package:dungeon_paper/app/widgets/dialogs/debilities_dialog.dart';
|
||||
import 'package:dungeon_paper/core/dw_icons.dart';
|
||||
@@ -43,8 +44,9 @@ class HomeCharacterExtras extends StatelessWidget with CharacterProviderMixin {
|
||||
MenuEntry(
|
||||
value: 'class',
|
||||
icon: Icon(CharacterClass.genericIcon),
|
||||
label:
|
||||
Text(tr.generic.changeEntity(tr.entity(tn(CharacterClass)))),
|
||||
label: Text(
|
||||
tr.generic.changeEntity(tr.entity(tn(CharacterClass))),
|
||||
),
|
||||
onSelect: () => _openCharClass(context),
|
||||
),
|
||||
MenuEntry(
|
||||
@@ -53,6 +55,35 @@ class HomeCharacterExtras extends StatelessWidget with CharacterProviderMixin {
|
||||
label: Text(tr.generic.changeEntity(tr.entity(tn(Race)))),
|
||||
onSelect: () => _openRace(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.text_snippet),
|
||||
tooltip: tr.home.menu.bio,
|
||||
onPressed: () => _openBio(context),
|
||||
),
|
||||
CharacterProvider.consumer(
|
||||
(context, controller, _) => IconButton(
|
||||
onPressed: () => _openBondsFlags(context),
|
||||
icon: Transform.scale(
|
||||
scaleX: -1,
|
||||
child: const Icon(Icons.handshake),
|
||||
),
|
||||
tooltip: SessionMark.categoryTitle(
|
||||
bonds: controller.maybeCurrent?.bonds ?? [],
|
||||
flags: controller.maybeCurrent?.flags ?? [],
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => _openDebilities(context),
|
||||
icon: const Icon(Icons.personal_injury),
|
||||
tooltip: tr.home.menu.debilities,
|
||||
),
|
||||
MenuButton<String>(
|
||||
icon: const Icon(Icons.settings),
|
||||
tooltip: tr.home.menu.character.settings,
|
||||
items: [
|
||||
MenuEntry(
|
||||
value: 'roll_buttons',
|
||||
icon: const Icon(DwIcons.dice_d6),
|
||||
@@ -65,34 +96,20 @@ class HomeCharacterExtras extends StatelessWidget with CharacterProviderMixin {
|
||||
label: Text(tr.home.menu.character.theme),
|
||||
onSelect: () => _openThemeSelect(context),
|
||||
),
|
||||
MenuEntry(
|
||||
value: 'favorites_view',
|
||||
icon: const Icon(Icons.grid_view),
|
||||
label: Text(tr.home.menu.character.favoritesView),
|
||||
onSelect: () => _openFavoritesViewSelect(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.text_snippet),
|
||||
tooltip: tr.home.menu.bio,
|
||||
onPressed: () => _openBio(context),
|
||||
),
|
||||
CharacterProvider.consumer(
|
||||
(context, controller, _) => IconButton(
|
||||
onPressed: () => _openBondsFlags(context),
|
||||
icon:
|
||||
Transform.scale(scaleX: -1, child: const Icon(Icons.handshake)),
|
||||
tooltip: SessionMark.categoryTitle(
|
||||
bonds: controller.maybeCurrent?.bonds ?? [],
|
||||
flags: controller.maybeCurrent?.flags ?? [],
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => _openDebilities(context),
|
||||
icon: const Icon(Icons.personal_injury),
|
||||
tooltip: tr.home.menu.debilities,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: null,
|
||||
icon: const Icon(Icons.groups),
|
||||
tooltip: tr.entityPlural(tn(Campaign)),
|
||||
),
|
||||
|
||||
// IconButton(
|
||||
// onPressed: null,
|
||||
// icon: const Icon(Icons.groups),
|
||||
// tooltip: tr.entityPlural(tn(Campaign)),
|
||||
// ),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -102,8 +119,10 @@ class HomeCharacterExtras extends StatelessWidget with CharacterProviderMixin {
|
||||
Routes.abilityScores,
|
||||
arguments: AbilityScoresFormArguments(
|
||||
abilityScores: charProvider.current.abilityScores,
|
||||
onChanged: (abilityScores) => charProvider.updateCharacter(
|
||||
charProvider.current.copyWith(abilityScores: abilityScores)),
|
||||
onChanged:
|
||||
(abilityScores) => charProvider.updateCharacter(
|
||||
charProvider.current.copyWith(abilityScores: abilityScores),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -112,9 +131,13 @@ class HomeCharacterExtras extends StatelessWidget with CharacterProviderMixin {
|
||||
Navigator.of(context).pushNamed(
|
||||
Routes.basicInfo,
|
||||
arguments: BasicInfoFormArguments(
|
||||
onChanged: (name, avatar) => charProvider.updateCharacter(
|
||||
charProvider.current.copyWith(displayName: name, avatarUrl: avatar),
|
||||
),
|
||||
onChanged:
|
||||
(name, avatar) => charProvider.updateCharacter(
|
||||
charProvider.current.copyWith(
|
||||
displayName: name,
|
||||
avatarUrl: avatar,
|
||||
),
|
||||
),
|
||||
name: charProvider.current.displayName,
|
||||
avatarUrl: charProvider.current.avatarUrl,
|
||||
),
|
||||
@@ -130,12 +153,14 @@ class HomeCharacterExtras extends StatelessWidget with CharacterProviderMixin {
|
||||
context,
|
||||
character: charProvider.current,
|
||||
preSelection: charProvider.current.race,
|
||||
onSelected: (race) => charProvider.updateCharacter(
|
||||
charProvider.current.copyWithInherited(
|
||||
race: race.copyWithInherited(
|
||||
favorite: charProvider.current.race.favorite),
|
||||
),
|
||||
),
|
||||
onSelected:
|
||||
(race) => charProvider.updateCharacter(
|
||||
charProvider.current.copyWithInherited(
|
||||
race: race.copyWithInherited(
|
||||
favorite: charProvider.current.race.favorite,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,37 +168,50 @@ class HomeCharacterExtras extends StatelessWidget with CharacterProviderMixin {
|
||||
ModelPages.openCharacterClassesList(
|
||||
context,
|
||||
character: charProvider.current,
|
||||
onSelected: (cls) => charProvider.updateCharacter(
|
||||
// TODO add a reset dialog to confirm + ask what to reset: moves, spells, alignment, rac
|
||||
charProvider.current.copyWithInherited(
|
||||
characterClass: cls,
|
||||
),
|
||||
),
|
||||
onSelected:
|
||||
(cls) => charProvider.updateCharacter(
|
||||
// TODO add a reset dialog to confirm + ask what to reset: moves, spells, alignment, rac
|
||||
charProvider.current.copyWithInherited(characterClass: cls),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openBondsFlags(BuildContext context) {
|
||||
showDialog(
|
||||
context: context, builder: (_) => const CharacterBondsFlagsDialog());
|
||||
context: context,
|
||||
builder: (_) => const CharacterBondsFlagsDialog(),
|
||||
);
|
||||
}
|
||||
|
||||
void _openDebilities(BuildContext context) {
|
||||
showDialog(
|
||||
context: context, builder: (_) => const CharacterDebilitiesDialog());
|
||||
context: context,
|
||||
builder: (_) => const CharacterDebilitiesDialog(),
|
||||
);
|
||||
}
|
||||
|
||||
void _openRollButtons(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => CustomRollButtonsDialog(
|
||||
character: charProvider.current,
|
||||
onChanged: (rollButtons) => charProvider.updateCharacter(
|
||||
charProvider.current.copyWith(
|
||||
settings: charProvider.current.settings
|
||||
.copyWith(rollButtons: rollButtons),
|
||||
builder:
|
||||
(_) => CustomRollButtonsDialog(
|
||||
character: charProvider.current,
|
||||
onChanged:
|
||||
(rollButtons) => charProvider.updateCharacter(
|
||||
charProvider.current.copyWith(
|
||||
settings: charProvider.current.settings.copyWith(
|
||||
rollButtons: rollButtons,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openFavoritesViewSelect(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => const CharacterFavoritesViewSelectDialog(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import 'package:dungeon_paper/app/data/models/character_settings.dart';
|
||||
import 'package:dungeon_paper/app/data/services/character_provider.dart';
|
||||
import 'package:dungeon_paper/app/widgets/molecules/dialog_controls.dart';
|
||||
import 'package:dungeon_paper/i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CharacterFavoritesViewSelectDialog extends StatefulWidget {
|
||||
const CharacterFavoritesViewSelectDialog({super.key});
|
||||
|
||||
@override
|
||||
State<CharacterFavoritesViewSelectDialog> createState() =>
|
||||
_CharacterFavoritesViewSelectDialogState();
|
||||
}
|
||||
|
||||
class _CharacterFavoritesViewSelectDialogState
|
||||
extends State<CharacterFavoritesViewSelectDialog>
|
||||
with CharacterProviderMixin {
|
||||
late FavoritesView value;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
value = char.settings.favoritesView;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('Select View'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
RadioListTile.adaptive(
|
||||
value: FavoritesView.cards,
|
||||
groupValue: value,
|
||||
onChanged: _onSelect,
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(Icons.grid_view),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: Text(tr.character.favoritesView.cards)),
|
||||
],
|
||||
),
|
||||
),
|
||||
RadioListTile.adaptive(
|
||||
value: FavoritesView.list,
|
||||
groupValue: value,
|
||||
onChanged: _onSelect,
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(Icons.list),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: Text(tr.character.favoritesView.list)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: DialogControls.save(
|
||||
context,
|
||||
onSave: () {
|
||||
charProvider.updateCharacter(
|
||||
char.copyWith(
|
||||
settings: char.settings.copyWith(favoritesView: value),
|
||||
),
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
onCancel: () => Navigator.of(context).pop(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onSelect(FavoritesView? value) {
|
||||
setState(() {
|
||||
this.value = value!;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1239,6 +1239,16 @@ class CharacterMenuHomeMessages {
|
||||
/// "Character Theme"
|
||||
/// ```
|
||||
String get theme => """Character Theme""";
|
||||
|
||||
/// ```dart
|
||||
/// "View Settings"
|
||||
/// ```
|
||||
String get settings => """View Settings""";
|
||||
|
||||
/// ```dart
|
||||
/// "Change Favorites View"
|
||||
/// ```
|
||||
String get favoritesView => """Change Favorites View""";
|
||||
}
|
||||
|
||||
class EmptyStateHomeMessages {
|
||||
@@ -1432,6 +1442,8 @@ class CharacterMessages {
|
||||
/// ```
|
||||
String get noCategory => """No Category""";
|
||||
ThemeCharacterMessages get theme => ThemeCharacterMessages(this);
|
||||
FavoritesViewCharacterMessages get favoritesView =>
|
||||
FavoritesViewCharacterMessages(this);
|
||||
}
|
||||
|
||||
class DataCharacterMessages {
|
||||
@@ -1536,6 +1548,21 @@ class ThemeCharacterMessages {
|
||||
String get defaultDark => """${_defaultTheme('dark')}""";
|
||||
}
|
||||
|
||||
class FavoritesViewCharacterMessages {
|
||||
final CharacterMessages _parent;
|
||||
const FavoritesViewCharacterMessages(this._parent);
|
||||
|
||||
/// ```dart
|
||||
/// "Cards View"
|
||||
/// ```
|
||||
String get cards => """Cards View""";
|
||||
|
||||
/// ```dart
|
||||
/// "List View"
|
||||
/// ```
|
||||
String get list => """List View""";
|
||||
}
|
||||
|
||||
class CharacterClassMessages {
|
||||
final Messages _parent;
|
||||
const CharacterClassMessages(this._parent);
|
||||
@@ -4145,6 +4172,8 @@ Map<String, String> get messagesMap => {
|
||||
"""home.menu.character.abilityScores""": """Ability Scores""",
|
||||
"""home.menu.character.customRolls""": """Quick-Roll Buttons""",
|
||||
"""home.menu.character.theme""": """Character Theme""",
|
||||
"""home.menu.character.settings""": """View Settings""",
|
||||
"""home.menu.character.favoritesView""": """Change Favorites View""",
|
||||
"""home.menu.bio""": """Character Biography""",
|
||||
"""home.menu.debilities""": """Debilities""",
|
||||
"""home.emptyState.guest.title""": """Sign in to get more features""",
|
||||
@@ -4188,6 +4217,8 @@ Map<String, String> get messagesMap => {
|
||||
"""character.header.separator""": """ ∙ """,
|
||||
"""character.noCategory""": """No Category""",
|
||||
"""character.theme.title""": """Character Theme""",
|
||||
"""character.favoritesView.cards""": """Cards View""",
|
||||
"""character.favoritesView.list""": """List View""",
|
||||
"""characterClass.baseLoad""": """Base Load""",
|
||||
"""characterClass.baseHp""": """Base HP""",
|
||||
"""characterClass.damageDice""": """Damage Dice""",
|
||||
|
||||
@@ -247,6 +247,8 @@ home:
|
||||
abilityScores: Ability Scores
|
||||
customRolls: Quick-Roll Buttons
|
||||
theme: Character Theme
|
||||
settings: View Settings
|
||||
favoritesView: Change Favorites View
|
||||
bio: Character Biography
|
||||
debilities: Debilities
|
||||
emptyState:
|
||||
@@ -307,6 +309,9 @@ character:
|
||||
_defaultTheme(String type): Default $type theme
|
||||
defaultLight: "${_defaultTheme('light')}"
|
||||
defaultDark: "${_defaultTheme('dark')}"
|
||||
favoritesView:
|
||||
cards: Cards View
|
||||
list: List View
|
||||
|
||||
characterClass:
|
||||
baseLoad: Base Load
|
||||
|
||||
@@ -1251,6 +1251,16 @@ class CharacterMenuHomeMessagesPlPL extends CharacterMenuHomeMessages {
|
||||
/// "Character Theme"
|
||||
/// ```
|
||||
String get theme => """Character Theme""";
|
||||
|
||||
/// ```dart
|
||||
/// "View Settings"
|
||||
/// ```
|
||||
String get settings => """View Settings""";
|
||||
|
||||
/// ```dart
|
||||
/// "Change Favorites View"
|
||||
/// ```
|
||||
String get favoritesView => """Change Favorites View""";
|
||||
}
|
||||
|
||||
class EmptyStateHomeMessagesPlPL extends EmptyStateHomeMessages {
|
||||
@@ -1445,6 +1455,8 @@ class CharacterMessagesPlPL extends CharacterMessages {
|
||||
/// ```
|
||||
String get noCategory => """No Category""";
|
||||
ThemeCharacterMessagesPlPL get theme => ThemeCharacterMessagesPlPL(this);
|
||||
FavoritesViewCharacterMessagesPlPL get favoritesView =>
|
||||
FavoritesViewCharacterMessagesPlPL(this);
|
||||
}
|
||||
|
||||
class DataCharacterMessagesPlPL extends DataCharacterMessages {
|
||||
@@ -1549,6 +1561,22 @@ class ThemeCharacterMessagesPlPL extends ThemeCharacterMessages {
|
||||
String get defaultDark => """${_defaultTheme('dark')}""";
|
||||
}
|
||||
|
||||
class FavoritesViewCharacterMessagesPlPL
|
||||
extends FavoritesViewCharacterMessages {
|
||||
final CharacterMessagesPlPL _parent;
|
||||
const FavoritesViewCharacterMessagesPlPL(this._parent) : super(_parent);
|
||||
|
||||
/// ```dart
|
||||
/// "Cards View"
|
||||
/// ```
|
||||
String get cards => """Cards View""";
|
||||
|
||||
/// ```dart
|
||||
/// "List View"
|
||||
/// ```
|
||||
String get list => """List View""";
|
||||
}
|
||||
|
||||
class CharacterClassMessagesPlPL extends CharacterClassMessages {
|
||||
final MessagesPlPL _parent;
|
||||
const CharacterClassMessagesPlPL(this._parent) : super(_parent);
|
||||
@@ -4259,6 +4287,8 @@ Map<String, String> get messagesPlPLMap => {
|
||||
"""home.menu.character.abilityScores""": """Ability Scores""",
|
||||
"""home.menu.character.customRolls""": """Quick-Roll Buttons""",
|
||||
"""home.menu.character.theme""": """Character Theme""",
|
||||
"""home.menu.character.settings""": """View Settings""",
|
||||
"""home.menu.character.favoritesView""": """Change Favorites View""",
|
||||
"""home.menu.bio""": """Character Biography""",
|
||||
"""home.menu.debilities""": """Debilities""",
|
||||
"""home.emptyState.guest.title""": """Sign in to get more features""",
|
||||
@@ -4302,6 +4332,8 @@ Map<String, String> get messagesPlPLMap => {
|
||||
"""character.header.separator""": """ ∙ """,
|
||||
"""character.noCategory""": """No Category""",
|
||||
"""character.theme.title""": """Character Theme""",
|
||||
"""character.favoritesView.cards""": """Cards View""",
|
||||
"""character.favoritesView.list""": """List View""",
|
||||
"""characterClass.baseLoad""": """Base Load""",
|
||||
"""characterClass.baseHp""": """Base HP""",
|
||||
"""characterClass.damageDice""": """Damage Dice""",
|
||||
|
||||
@@ -247,6 +247,8 @@ home:
|
||||
abilityScores: Ability Scores
|
||||
customRolls: Quick-Roll Buttons
|
||||
theme: Character Theme
|
||||
settings: View Settings
|
||||
favoritesView: Change Favorites View
|
||||
bio: Character Biography
|
||||
debilities: Debilities
|
||||
emptyState:
|
||||
@@ -307,6 +309,9 @@ character:
|
||||
_defaultTheme(String type): Default $type theme
|
||||
defaultLight: "${_defaultTheme('light')}"
|
||||
defaultDark: "${_defaultTheme('dark')}"
|
||||
favoritesView:
|
||||
cards: Cards View
|
||||
list: List View
|
||||
|
||||
characterClass:
|
||||
baseLoad: Base Load
|
||||
|
||||
@@ -1254,6 +1254,11 @@ class MenuHomeMessagesPtBR extends MenuHomeMessages {
|
||||
CharacterMenuHomeMessagesPtBR get character =>
|
||||
CharacterMenuHomeMessagesPtBR(this);
|
||||
|
||||
/// ```dart
|
||||
/// "Change Favorites View"
|
||||
/// ```
|
||||
String get favoritesView => """Change Favorites View""";
|
||||
|
||||
/// ```dart
|
||||
/// "Biografia do Personagem"
|
||||
/// ```
|
||||
@@ -1293,6 +1298,11 @@ class CharacterMenuHomeMessagesPtBR extends CharacterMenuHomeMessages {
|
||||
/// "Tema do Personagem"
|
||||
/// ```
|
||||
String get theme => """Tema do Personagem""";
|
||||
|
||||
/// ```dart
|
||||
/// "View Settings"
|
||||
/// ```
|
||||
String get settings => """View Settings""";
|
||||
}
|
||||
|
||||
class EmptyStateHomeMessagesPtBR extends EmptyStateHomeMessages {
|
||||
@@ -1488,6 +1498,8 @@ class CharacterMessagesPtBR extends CharacterMessages {
|
||||
/// ```
|
||||
String get noCategory => """Sem Categoria""";
|
||||
ThemeCharacterMessagesPtBR get theme => ThemeCharacterMessagesPtBR(this);
|
||||
FavoritesViewCharacterMessagesPtBR get favoritesView =>
|
||||
FavoritesViewCharacterMessagesPtBR(this);
|
||||
}
|
||||
|
||||
class DataCharacterMessagesPtBR extends DataCharacterMessages {
|
||||
@@ -1592,6 +1604,22 @@ class ThemeCharacterMessagesPtBR extends ThemeCharacterMessages {
|
||||
String get defaultDark => """${_defaultTheme('escuro')}""";
|
||||
}
|
||||
|
||||
class FavoritesViewCharacterMessagesPtBR
|
||||
extends FavoritesViewCharacterMessages {
|
||||
final CharacterMessagesPtBR _parent;
|
||||
const FavoritesViewCharacterMessagesPtBR(this._parent) : super(_parent);
|
||||
|
||||
/// ```dart
|
||||
/// "Cards View"
|
||||
/// ```
|
||||
String get cards => """Cards View""";
|
||||
|
||||
/// ```dart
|
||||
/// "List View"
|
||||
/// ```
|
||||
String get list => """List View""";
|
||||
}
|
||||
|
||||
class CharacterClassMessagesPtBR extends CharacterClassMessages {
|
||||
final MessagesPtBR _parent;
|
||||
const CharacterClassMessagesPtBR(this._parent) : super(_parent);
|
||||
@@ -4302,6 +4330,8 @@ Map<String, String> get messagesPtBRMap => {
|
||||
"""home.menu.character.abilityScores""": """Pontuações de Habilidade""",
|
||||
"""home.menu.character.customRolls""": """Botões de Rolagem Rápida""",
|
||||
"""home.menu.character.theme""": """Tema do Personagem""",
|
||||
"""home.menu.character.settings""": """View Settings""",
|
||||
"""home.menu.favoritesView""": """Change Favorites View""",
|
||||
"""home.menu.bio""": """Biografia do Personagem""",
|
||||
"""home.menu.debilities""": """Debilidades""",
|
||||
"""home.emptyState.guest.title""": """Entre para obter mais recursos""",
|
||||
@@ -4345,6 +4375,8 @@ Map<String, String> get messagesPtBRMap => {
|
||||
"""character.header.separator""": """ ∙ """,
|
||||
"""character.noCategory""": """Sem Categoria""",
|
||||
"""character.theme.title""": """Tema do Personagem""",
|
||||
"""character.favoritesView.cards""": """Cards View""",
|
||||
"""character.favoritesView.list""": """List View""",
|
||||
"""characterClass.baseLoad""": """Carga Base""",
|
||||
"""characterClass.baseHp""": """HP Base""",
|
||||
"""characterClass.damageDice""": """Dados de Dano""",
|
||||
|
||||
@@ -267,6 +267,9 @@ home:
|
||||
abilityScores: Pontuações de Habilidade
|
||||
customRolls: Botões de Rolagem Rápida
|
||||
theme: Tema do Personagem
|
||||
# TODO translate
|
||||
settings: View Settings
|
||||
favoritesView: Change Favorites View
|
||||
bio: Biografia do Personagem
|
||||
debilities: Debilidades
|
||||
emptyState:
|
||||
@@ -327,6 +330,10 @@ character:
|
||||
_defaultTheme(String type): Tema padrão $type
|
||||
defaultLight: "${_defaultTheme('claro')}"
|
||||
defaultDark: "${_defaultTheme('escuro')}"
|
||||
# TODO translate
|
||||
favoritesView:
|
||||
cards: Cards View
|
||||
list: List View
|
||||
|
||||
characterClass:
|
||||
baseLoad: Carga Base
|
||||
|
||||
@@ -37,6 +37,7 @@ void main() async {
|
||||
options.dsn = secrets.sentryDsn;
|
||||
options.tracesSampleRate = kDebugMode ? 1.0 : 0.0;
|
||||
options.environment = kDebugMode ? 'development' : 'release';
|
||||
options.debug = false;
|
||||
},
|
||||
appRunner: _init,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user