Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New behaviour and animation for the "New transaction" button #275

22 changes: 19 additions & 3 deletions lib/app/home/dashboard.page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:monekin/app/accounts/account_form.dart';
import 'package:monekin/app/accounts/details/account_details.dart';
Expand Down Expand Up @@ -42,11 +43,25 @@ class _DashboardPageState extends State<DashboardPage> {
final ScrollController _scrollController = ScrollController();
bool showSmallHeader = false;

bool isFloatingButtonExtended = true;

@override
void initState() {
super.initState();

_scrollController.addListener(_setSmallHeaderVisible);
_scrollController.addListener(() {
_setSmallHeaderVisible();

bool shouldExtendButton = _scrollController.offset <= 10 ||
_scrollController.position.userScrollDirection !=
ScrollDirection.reverse;

if (isFloatingButtonExtended != shouldExtendButton) {
setState(() {
isFloatingButtonExtended = shouldExtendButton;
});
}
});
}

@override
Expand Down Expand Up @@ -82,8 +97,9 @@ class _DashboardPageState extends State<DashboardPage> {
return Scaffold(
appBar: EmptyAppBar(
color: Theme.of(context).colorSchemeExtended.dashboardHeader),
floatingActionButton:
hideDrawerAndFloatingButton ? null : const NewTransactionButton(),
floatingActionButton: hideDrawerAndFloatingButton
? null
: NewTransactionButton(isExtended: isFloatingButtonExtended),
drawer: hideDrawerAndFloatingButton
? null
: Drawer(
Expand Down
34 changes: 19 additions & 15 deletions lib/app/home/widgets/new_transaction_fl_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import 'package:flutter/material.dart';
import 'package:monekin/app/accounts/account_form.dart';
import 'package:monekin/app/transactions/form/transaction_form.page.dart';
import 'package:monekin/core/database/services/transaction/transaction_service.dart';
import 'package:monekin/core/presentation/animations/animated_expanded.dart';
import 'package:monekin/core/presentation/widgets/confirm_dialog.dart';
import 'package:monekin/core/routes/route_utils.dart';
import 'package:monekin/i18n/translations.g.dart';

class NewTransactionButton extends StatelessWidget {
const NewTransactionButton({super.key, this.isExtended = false});
const NewTransactionButton({
super.key,
this.isExtended = true,
});

final bool isExtended;

Expand All @@ -22,7 +26,7 @@ class NewTransactionButton extends StatelessWidget {
).then((value) {
if (value != true) return;

RouteUtils.pushRoute(context, AccountFormPage());
RouteUtils.pushRoute(context, const AccountFormPage());
});
}

Expand All @@ -41,20 +45,20 @@ class NewTransactionButton extends StatelessWidget {

@override
Widget build(BuildContext context) {
if (isExtended) {
return FloatingActionButton.extended(
heroTag: null,
onPressed: () => _onPressed(context),
label: Text(t.transaction.create),
icon: const Icon(Icons.add_rounded),
);
}

return FloatingActionButton(
heroTag: 'new-transaction-floating-button',
tooltip: t.transaction.create,
final t = Translations.of(context);

return FloatingActionButton.extended(
heroTag: null,
onPressed: () => _onPressed(context),
child: const Icon(Icons.add_rounded),
icon: const Icon(Icons.add_rounded),
extendedPadding: const EdgeInsetsDirectional.only(start: 16, end: 16),
extendedIconLabelSpacing: isExtended ? 8 : 0,
label: AnimatedExpanded(
duration: const Duration(milliseconds: 250),
expand: isExtended,
axis: Axis.horizontal,
child: Text(t.transaction.create),
),
);
}
}
2 changes: 1 addition & 1 deletion lib/app/layout/navigation_sidebar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class NavigationSidebarState extends State<NavigationSidebar> {
leading: const Column(
children: [
SizedBox(height: 16),
NewTransactionButton(),
NewTransactionButton(isExtended: false),
SizedBox(height: 16),
],
),
Expand Down
17 changes: 16 additions & 1 deletion lib/app/transactions/transactions.page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:monekin/app/home/widgets/new_transaction_fl_button.dart';
import 'package:monekin/app/layout/tabs.dart';
Expand Down Expand Up @@ -36,6 +37,8 @@ class _TransactionsPageState extends State<TransactionsPage> {
FocusNode searchFocusNode = FocusNode();
final searchController = TextEditingController();

bool isFloatingButtonExtended = true;

List<MoneyTransaction> selectedTransactions = [];

@override
Expand Down Expand Up @@ -143,7 +146,8 @@ class _TransactionsPageState extends State<TransactionsPage> {
icon: const Icon(Icons.filter_alt_outlined)),
],
),
floatingActionButton: const NewTransactionButton(isExtended: true),
floatingActionButton:
NewTransactionButton(isExtended: isFloatingButtonExtended),
body: Column(
children: [
if (filters.hasFilter) ...[
Expand Down Expand Up @@ -250,6 +254,17 @@ class _TransactionsPageState extends State<TransactionsPage> {
selectedTransactions = [tr];
});
},
onScrollChange: (controller) {
bool shouldExtendButton = controller.offset <= 10 ||
controller.position.userScrollDirection !=
ScrollDirection.reverse;

if (isFloatingButtonExtended != shouldExtendButton) {
setState(() {
isFloatingButtonExtended = shouldExtendButton;
});
}
},
onTap: selectedTransactions.isEmpty ? null : toggleTransaction,
onEmptyList: NoResults(
title: filters.hasFilter ? null : t.general.empty_warn,
Expand Down
18 changes: 12 additions & 6 deletions lib/app/transactions/widgets/transaction_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class TransactionListComponent extends StatefulWidget {
this.onTap,
this.selectedTransactions = const [],
this.onTransactionsLoaded,
this.onScrollChange,
});

final TransactionFilters filters;
Expand All @@ -52,6 +53,8 @@ class TransactionListComponent extends StatefulWidget {

final Object? Function(MoneyTransaction tr)? heroTagBuilder;

final void Function(ScrollController controller)? onScrollChange;

/// Action to trigger when a transaction tile is long pressed. If `null`,
/// the tile will display a modal with some quick actions for
/// this transaction
Expand All @@ -72,21 +75,24 @@ class TransactionListComponent extends StatefulWidget {
}

class _TransactionListComponentState extends State<TransactionListComponent> {
ScrollController listController = ScrollController();
ScrollController listScrollController = ScrollController();

int currentPage = 1;
bool isEnabled = true;

@override
void initState() {
super.initState();

listController.addListener(() {
if (listController.offset >= listController.position.maxScrollExtent &&
!listController.position.outOfRange) {
listScrollController.addListener(() {
if (listScrollController.offset >=
listScrollController.position.maxScrollExtent &&
!listScrollController.position.outOfRange) {
currentPage += 1;

setState(() {});
}

widget.onScrollChange?.call(listScrollController);
});
}

Expand Down Expand Up @@ -158,7 +164,7 @@ class _TransactionListComponentState extends State<TransactionListComponent> {
return ListView.separated(
physics: const BouncingScrollPhysics(),
itemCount: transactions.length + 1,
controller: listController,
controller: listScrollController,
shrinkWrap: true,
itemBuilder: (context, index) {
if (transactions.isEmpty) return Container();
Expand Down