250 lines
7.7 KiB
Dart
250 lines
7.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:okane/screen.dart';
|
|
import 'package:okane/ui/pages/account/account.dart';
|
|
import 'package:okane/ui/pages/budgets/budget_details.dart';
|
|
import 'package:okane/ui/pages/budgets/budgets.dart';
|
|
import 'package:okane/ui/pages/template_list.dart';
|
|
import 'package:okane/ui/pages/transaction_details.dart';
|
|
import 'package:okane/ui/pages/transaction_list.dart';
|
|
import 'package:okane/ui/state/core.dart';
|
|
import 'package:okane/ui/widgets/account_indicator.dart';
|
|
|
|
enum OkanePage { accounts, transactions, beneficiaries, templates, budgets }
|
|
|
|
typedef OkanePageBuilder = Widget Function(bool);
|
|
|
|
class OkanePageItem {
|
|
final OkanePage page;
|
|
final IconData icon;
|
|
final String label;
|
|
final Widget child;
|
|
final OkanePageBuilder? details;
|
|
final bool showAccountName;
|
|
|
|
const OkanePageItem(
|
|
this.page,
|
|
this.icon,
|
|
this.label,
|
|
this.child,
|
|
this.details,
|
|
this.showAccountName,
|
|
);
|
|
|
|
bool _isEnabled(int? accountIndex) {
|
|
if (showAccountName) {
|
|
return accountIndex != null;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
NavigationDestination toDestination(int? accountIndex) =>
|
|
NavigationDestination(
|
|
icon: Icon(icon),
|
|
label: label,
|
|
enabled: _isEnabled(accountIndex),
|
|
);
|
|
|
|
NavigationRailDestination toRailDestination(int? accountIndex) =>
|
|
NavigationRailDestination(
|
|
icon: Icon(icon),
|
|
label: Text(label),
|
|
disabled: !_isEnabled(accountIndex),
|
|
);
|
|
}
|
|
|
|
final _pages = <OkanePageItem>[
|
|
OkanePageItem(
|
|
OkanePage.accounts,
|
|
Icons.account_box,
|
|
"Accounts",
|
|
AccountListPage(isPage: false),
|
|
null,
|
|
false,
|
|
),
|
|
OkanePageItem(
|
|
OkanePage.transactions,
|
|
Icons.monetization_on_rounded,
|
|
"Transactions",
|
|
TransactionListPage(),
|
|
(_) => TransactionDetailsPage(),
|
|
true,
|
|
),
|
|
OkanePageItem(
|
|
OkanePage.beneficiaries,
|
|
Icons.person,
|
|
"Beneficiaries",
|
|
Container(),
|
|
null,
|
|
true,
|
|
),
|
|
OkanePageItem(
|
|
OkanePage.templates,
|
|
Icons.list,
|
|
"Templates",
|
|
TemplateListPage(),
|
|
null,
|
|
true,
|
|
),
|
|
OkanePageItem(
|
|
OkanePage.budgets,
|
|
Icons.pie_chart,
|
|
"Budgets",
|
|
BudgetListPage(),
|
|
(_) => BudgetDetailsPage(),
|
|
true,
|
|
),
|
|
];
|
|
|
|
class OkaneNavigationRail extends StatelessWidget {
|
|
const OkaneNavigationRail({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return BlocBuilder<CoreCubit, CoreState>(
|
|
builder:
|
|
(context, state) => NavigationRail(
|
|
onDestinationSelected:
|
|
(i) => context.read<CoreCubit>().setPage(_pages[i].page),
|
|
destinations:
|
|
_pages
|
|
.map((p) => p.toRailDestination(state.activeAccountIndex))
|
|
.toList(),
|
|
selectedIndex: _pages.indexWhere((p) => p.page == state.activePage),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class OkaneNavigationBar extends StatelessWidget {
|
|
const OkaneNavigationBar({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return BlocBuilder<CoreCubit, CoreState>(
|
|
builder:
|
|
(context, state) => NavigationBar(
|
|
onDestinationSelected:
|
|
(i) => context.read<CoreCubit>().setPage(_pages[i].page),
|
|
destinations:
|
|
_pages
|
|
.map((p) => p.toDestination(state.activeAccountIndex))
|
|
.toList(),
|
|
selectedIndex: _pages.indexWhere((p) => p.page == state.activePage),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class OkaneNavigationDrawer extends StatelessWidget {
|
|
const OkaneNavigationDrawer({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return BlocBuilder<CoreCubit, CoreState>(
|
|
builder:
|
|
(context, state) => Drawer(
|
|
child: ListView(
|
|
children:
|
|
_pages
|
|
.map(
|
|
(p) => ListTile(
|
|
title: Text(p.label),
|
|
leading: Icon(p.icon),
|
|
selected: p.page == state.activePage,
|
|
onTap: () {
|
|
context.read<CoreCubit>().setPage(p.page);
|
|
Navigator.of(context).pop();
|
|
},
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class OkaneNavigationLayout extends StatelessWidget {
|
|
const OkaneNavigationLayout({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final screenSize = getScreenSize(context);
|
|
return BlocBuilder<CoreCubit, CoreState>(
|
|
builder:
|
|
(_, state) => IndexedStack(
|
|
index: _pages.indexWhere((p) => p.page == state.activePage),
|
|
children:
|
|
_pages
|
|
.map(
|
|
(p) => switch (screenSize) {
|
|
ScreenSize.small => Column(
|
|
children: [
|
|
SizedBox(
|
|
height: 50,
|
|
child: Padding(
|
|
padding: EdgeInsets.all(8),
|
|
child: Row(
|
|
children: [
|
|
IconButton(
|
|
icon: Icon(Icons.menu),
|
|
onPressed: () {
|
|
Scaffold.of(context).openDrawer();
|
|
},
|
|
),
|
|
|
|
if (p.showAccountName &&
|
|
state.activeAccountIndex != null)
|
|
Padding(
|
|
padding: EdgeInsets.only(left: 8),
|
|
child: Text(
|
|
state
|
|
.accounts[state
|
|
.activeAccountIndex!]
|
|
.name!,
|
|
style:
|
|
Theme.of(
|
|
context,
|
|
).textTheme.titleLarge,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
Expanded(child: p.child),
|
|
],
|
|
),
|
|
ScreenSize.normal => Column(
|
|
children: [
|
|
if (p.showAccountName &&
|
|
state.activeAccountIndex != null)
|
|
AccountIndicator(
|
|
accountName:
|
|
state
|
|
.accounts[state.activeAccountIndex!]
|
|
.name!,
|
|
),
|
|
Expanded(
|
|
child:
|
|
p.details != null
|
|
? Row(
|
|
children: [
|
|
Expanded(child: p.child),
|
|
Expanded(child: p.details!(false)),
|
|
],
|
|
)
|
|
: p.child,
|
|
),
|
|
],
|
|
),
|
|
},
|
|
)
|
|
.toList(),
|
|
),
|
|
);
|
|
}
|
|
}
|