Skip to content

Commit

Permalink
Merge pull request #122 from enrique-lozano/feat/ui-improvements
Browse files Browse the repository at this point in the history
Details page improvements
  • Loading branch information
enrique-lozano authored Feb 24, 2024
2 parents 67376f5 + e12d3df commit d6050ca
Show file tree
Hide file tree
Showing 22 changed files with 1,330 additions and 1,061 deletions.
268 changes: 211 additions & 57 deletions lib/app/accounts/account_selector.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import 'package:collection/collection.dart';
import 'package:drift/drift.dart' as drift;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:monekin/core/database/app_db.dart';
import 'package:monekin/core/database/services/account/account_service.dart';
import 'package:monekin/core/models/account/account.dart';
import 'package:monekin/core/models/supported-icon/icon_displayer.dart';
import 'package:monekin/core/presentation/app_colors.dart';
import 'package:monekin/core/presentation/widgets/bottomSheetFooter.dart';
import 'package:monekin/core/presentation/widgets/modal_container.dart';
import 'package:monekin/core/utils/color_utils.dart';
import 'package:monekin/i18n/translations.g.dart';

import '../../core/presentation/widgets/icon_displayer_widgets.dart';

Future<List<Account>?> showAccountSelectorBottomSheet(
BuildContext context, AccountSelector accountSelector) {
BuildContext context, AccountSelectorModal accountSelector) {
return showModalBottomSheet<List<Account>>(
context: context,
showDragHandle: true,
Expand All @@ -20,13 +26,14 @@ Future<List<Account>?> showAccountSelectorBottomSheet(
);
}

class AccountSelector extends StatefulWidget {
const AccountSelector(
{super.key,
required this.allowMultiSelection,
required this.filterSavingAccounts,
this.includeArchivedAccounts = true,
this.selectedAccounts = const []});
class AccountSelectorModal extends StatefulWidget {
const AccountSelectorModal({
super.key,
required this.allowMultiSelection,
required this.filterSavingAccounts,
this.includeArchivedAccounts = true,
this.selectedAccounts = const [],
});

final bool allowMultiSelection;
final bool filterSavingAccounts;
Expand All @@ -35,10 +42,10 @@ class AccountSelector extends StatefulWidget {
final List<Account> selectedAccounts;

@override
State<AccountSelector> createState() => _AccountSelectorState();
State<AccountSelectorModal> createState() => _AccountSelectorModalState();
}

class _AccountSelectorState extends State<AccountSelector> {
class _AccountSelectorModalState extends State<AccountSelectorModal> {
List<Account>? allAccounts;

late List<Account> selectedAccounts;
Expand Down Expand Up @@ -85,53 +92,56 @@ class _AccountSelectorState extends State<AccountSelector> {
));
}

return Column(
mainAxisSize: MainAxisSize.min,
children: [
...List.generate(allAccounts!.length, (index) {
final account = allAccounts![index];

if (!widget.allowMultiSelection) {
return RadioListTile(
value: account.id,
title: Text(account.name),
secondary: account.displayIcon(context),
groupValue: selectedAccounts.firstOrNull?.id,
onChanged: (value) {
setState(() {
selectedAccounts = [account];

Navigator.of(context).pop(selectedAccounts);
});
},
);
} else {
return CheckboxListTile(
value:
selectedAccounts.map((e) => e.id).contains(account.id),
title: Text(account.name),
secondary: account.displayIcon(context),
onChanged: (value) {
if (value == true) {
selectedAccounts.add(account);
} else {
selectedAccounts
.removeWhere((element) => element.id == account.id);
}

setState(() {});
},
);
}
}),
if (widget.allowMultiSelection) ...[
const SizedBox(height: 14),
BottomSheetFooter(
onSaved: selectedAccounts.isNotEmpty
? () => Navigator.of(context).pop(selectedAccounts)
: null)
]
],
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...List.generate(allAccounts!.length, (index) {
final account = allAccounts![index];

if (!widget.allowMultiSelection) {
return RadioListTile(
value: account.id,
title: Text(account.name),
secondary: account.displayIcon(context),
groupValue: selectedAccounts.firstOrNull?.id,
onChanged: (value) {
setState(() {
selectedAccounts = [account];

Navigator.of(context).pop(selectedAccounts);
});
},
);
} else {
return CheckboxListTile(
value: selectedAccounts
.map((e) => e.id)
.contains(account.id),
title: Text(account.name),
secondary: account.displayIcon(context),
onChanged: (value) {
if (value == true) {
selectedAccounts.add(account);
} else {
selectedAccounts.removeWhere(
(element) => element.id == account.id);
}

setState(() {});
},
);
}
}),
if (widget.allowMultiSelection) ...[
const SizedBox(height: 14),
BottomSheetFooter(
onSaved: selectedAccounts.isNotEmpty
? () => Navigator.of(context).pop(selectedAccounts)
: null)
]
],
),
);
} else {
return const LinearProgressIndicator();
Expand All @@ -140,3 +150,147 @@ class _AccountSelectorState extends State<AccountSelector> {
);
}
}

class AccountSelector extends StatefulWidget {
const AccountSelector(
this.params, {
super.key,
});

final IconDisplayerSelectorData<Account> params;

@override
State<AccountSelector> createState() => _AccountSelectorState();
}

class _AccountSelectorState extends State<AccountSelector> {
List<CategoryButtonSelector> buildAccountsOptions({
required List<Account>? selectedItems,
}) {
return widget.params.availableItems!.map((accountToDisplay) {
final isAccountSelected = selectedItems == null ||
selectedItems!.any((cat) => cat.id == accountToDisplay.id);

return CategoryButtonSelector(
maxTextSize: widget.params.iconSize + widget.params.iconPadding * 2,
iconWidget: accountToDisplay.displayIcon(
context,
size: widget.params.iconSize,
padding: widget.params.iconPadding,
isOutline: isAccountSelected,
onTap: () {
HapticFeedback.lightImpact();

if (!widget.params.multiSelection) {
selectedItems = [accountToDisplay];

setState(() {});

if (widget.params.onChange != null) {
widget.params.onChange!(selectedItems);
}
return;
}

if (!isAccountSelected) {
if (selectedItems == null) {
selectedItems = [accountToDisplay];
} else {
selectedItems!.add(accountToDisplay);

if (selectedItems!.length ==
widget.params.availableItems!.length) {
selectedItems = null;
}
}
} else {
selectedItems ??= [...widget.params.availableItems!];

selectedItems!
.removeWhere((element) => element.id == accountToDisplay.id);
}

setState(() {});

if (widget.params.onChange != null) {
widget.params.onChange!(selectedItems);
}
},
),
label: accountToDisplay.name,
);
}).toList();
}

CategoryButtonSelector buildSelectAllButton(
BuildContext context, {
required List<Account>? selectedAccounts,
}) {
final t = Translations.of(context);

return CategoryButtonSelector(
maxTextSize: widget.params.iconSize + widget.params.iconPadding * 2,
iconWidget: IconDisplayer(
icon: Icons.select_all,
displayMode: IconDisplayMode.polygon,
size: widget.params.iconSize,
padding: widget.params.iconPadding,
isOutline: selectedAccounts == null,
secondaryColor: AppColors.of(context).background.darken(
Theme.of(context).brightness == Brightness.dark ? 0.6 : 0.1,
),
mainColor: AppColors.of(context).onBackground,
onTap: () {
if (selectedAccounts == null) {
selectedAccounts = [];
} else {
selectedAccounts = null;
}

setState(() {});

HapticFeedback.lightImpact();

if (widget.params.onChange != null) {
widget.params.onChange!(selectedAccounts);
}
},
),
label: t.categories.select.all_short,
);
}

@override
Widget build(BuildContext context) {
List<Account>? selectedAccounts = widget.params.selectedItems;

final extraHeaderButtonsWithSameSize = widget.params.extraHeaderButtons
?.map(
(e) => e.copyWith(
iconWidget: e.iconWidget.copyWith(
size: widget.params.iconSize,
padding: widget.params.iconPadding,
),
),
)
.toList();

return Builder(builder: (context) {
if (widget.params.availableItems == null) {
return Container();
}

return IconDisplayerSelectorRow(
direction: widget.params.direction,
extraHeaderButtons: [
if (widget.params.direction == Axis.horizontal)
buildSelectAllButton(context, selectedAccounts: selectedAccounts),
if (extraHeaderButtonsWithSameSize != null)
...extraHeaderButtonsWithSameSize
],
scrollableOptions:
buildAccountsOptions(selectedItems: selectedAccounts),
);
});
}
}
Loading

0 comments on commit d6050ca

Please sign in to comment.