Add scrollbars

This commit is contained in:
Hillel Coren 2021-03-09 21:26:55 +02:00
parent ea13825026
commit 17cfc3d478
7 changed files with 63 additions and 75 deletions

View File

@ -56,11 +56,13 @@ class ScrollableListViewBuilder extends StatefulWidget {
Key key,
@required this.itemBuilder,
@required this.itemCount,
this.separatorBuilder,
this.scrollController,
this.padding,
}) : super(key: key);
final IndexedWidgetBuilder itemBuilder;
final IndexedWidgetBuilder separatorBuilder;
final int itemCount;
final ScrollController scrollController;
final EdgeInsetsGeometry padding;
@ -92,13 +94,22 @@ class _ScrollableListViewBuilderState extends State<ScrollableListViewBuilder> {
onEnter: (event) => setState(() => _isHovered = true),
onExit: (event) => setState(() => _isHovered = false),
child: Scrollbar(
child: ListView.builder(
padding: widget.padding,
itemBuilder: widget.itemBuilder,
itemCount: widget.itemCount,
controller: widget.scrollController ?? _scrollController,
shrinkWrap: true,
),
child: widget.separatorBuilder != null
? ListView.separated(
separatorBuilder: widget.separatorBuilder,
padding: widget.padding,
itemBuilder: widget.itemBuilder,
itemCount: widget.itemCount,
controller: widget.scrollController ?? _scrollController,
shrinkWrap: true,
)
: ListView.builder(
padding: widget.padding,
itemBuilder: widget.itemBuilder,
itemCount: widget.itemCount,
controller: widget.scrollController ?? _scrollController,
shrinkWrap: true,
),
controller: widget.scrollController ?? _scrollController,
isAlwaysShown: _isHovered,
),

View File

@ -17,6 +17,7 @@ import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_filter.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/presenters/entity_presenter.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/app/tables/app_data_table.dart';
import 'package:invoiceninja_flutter/ui/app/tables/app_paginated_data_table.dart';
import 'package:invoiceninja_flutter/ui/app/tables/entity_datatable.dart';
@ -54,14 +55,11 @@ class EntityList extends StatefulWidget {
class _EntityListState extends State<EntityList> {
EntityDataTableSource dataTableSource;
ScrollController _scrollController;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
final entityType = widget.entityType;
final state = widget.state;
final entityList = widget.entityList;
@ -95,12 +93,6 @@ class _EntityListState extends State<EntityList> {
dataTableSource.notifyListeners();
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final store = StoreProvider.of<AppState>(context);
@ -157,32 +149,28 @@ class _EntityListState extends State<EntityList> {
fit: FlexFit.loose,
child: entityList.isEmpty
? HelpText(AppLocalization.of(context).noRecordsFound)
: AppScrollbar(
controller: _scrollController,
child: ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 25),
controller: _scrollController,
separatorBuilder: (context, index) =>
(index == 0 || index == entityList.length)
? SizedBox()
: ListDivider(),
itemCount: entityList.length + 2,
itemBuilder: (BuildContext context, index) {
if (index == 0 || index == entityList.length + 1) {
return Container(
color: Theme.of(context).cardColor,
height: 25,
);
} else {
return widget.itemBuilder(context, index - 1);
}
},
),
: ScrollableListViewBuilder(
padding: const EdgeInsets.symmetric(vertical: 25),
separatorBuilder: (context, index) =>
(index == 0 || index == entityList.length)
? SizedBox()
: ListDivider(),
itemCount: entityList.length + 2,
itemBuilder: (BuildContext context, index) {
if (index == 0 || index == entityList.length + 1) {
return Container(
color: Theme.of(context).cardColor,
height: 25,
);
} else {
return widget.itemBuilder(context, index - 1);
}
},
) /*DraggableScrollbar.semicircle(
backgroundColor: Theme.of(context).backgroundColor,
scrollbarTimeToFade: Duration(seconds: 1),
controller: _scrollController,
child: ListView.separated(
child: ScrollableListViewBuilder(
padding: const EdgeInsets.symmetric(vertical: 25),
controller: _scrollController,
separatorBuilder: (context, index) =>

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/lists/activity_list_tile.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/client/view/client_view_vm.dart';
class ClientViewActivity extends StatefulWidget {
@ -31,7 +32,7 @@ class _ClientViewActivityState extends State<ClientViewActivity> {
return LoadingIndicator();
}
return ListView.separated(
return ScrollableListViewBuilder(
itemCount: activities.length,
padding: const EdgeInsets.symmetric(vertical: 16),
separatorBuilder: (context, index) => ListDivider(),

View File

@ -7,6 +7,7 @@ import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/client/view/client_view_vm.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:invoiceninja_flutter/utils/icons.dart';
@ -40,8 +41,7 @@ class _ClientViewLedgerState extends State<ClientViewLedger> {
return LoadingIndicator();
}
return ListView.separated(
shrinkWrap: true,
return ScrollableListViewBuilder(
padding: const EdgeInsets.symmetric(vertical: 16),
itemCount: ledgers.length + 1,
separatorBuilder: (context, index) => ListDivider(),

View File

@ -7,6 +7,7 @@ import 'package:invoiceninja_flutter/redux/dashboard/dashboard_actions.dart';
import 'package:invoiceninja_flutter/redux/dashboard/dashboard_sidebar_selectors.dart';
import 'package:invoiceninja_flutter/ui/app/help_text.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/expense/expense_list_item.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_list_item.dart';
import 'package:invoiceninja_flutter/ui/payment/payment_list_item.dart';
@ -109,8 +110,7 @@ class InvoiceSidebar extends StatelessWidget {
(upcomingInvoices.isNotEmpty ? ' (${upcomingInvoices.length})' : ''),
list1: upcomingInvoices.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: upcomingInvoices.length,
itemBuilder: (BuildContext context, int index) {
return InvoiceListItem(
@ -124,8 +124,7 @@ class InvoiceSidebar extends StatelessWidget {
(pastDueInvoices.isNotEmpty ? ' (${pastDueInvoices.length})' : ''),
list2: pastDueInvoices.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: pastDueInvoices.length,
itemBuilder: (BuildContext context, int index) {
return InvoiceListItem(
@ -140,8 +139,7 @@ class InvoiceSidebar extends StatelessWidget {
: localization.selectedInvoices + ' (${selectedIds.length})',
list3: (selectedIds ?? <String>[]).isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: selectedIds?.length,
itemBuilder: (BuildContext context, int index) {
final invoice = state.invoiceState.map[selectedIds[index]];
@ -179,8 +177,7 @@ class PaymentSidebar extends StatelessWidget {
(recentPayments.isNotEmpty ? ' (${recentPayments.length})' : ''),
list1: recentPayments.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: recentPayments.length,
itemBuilder: (BuildContext context, int index) {
return PaymentListItem(
@ -195,8 +192,7 @@ class PaymentSidebar extends StatelessWidget {
: localization.selectedPayments + ' (${selectedIds.length})',
list3: (selectedIds ?? <String>[]).isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: selectedIds?.length,
itemBuilder: (BuildContext context, int index) {
final payment = state.paymentState.map[selectedIds[index]];
@ -238,8 +234,7 @@ class QuoteSidebar extends StatelessWidget {
(upcomingQuotes.isNotEmpty ? ' (${upcomingQuotes.length})' : ''),
list1: upcomingQuotes.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: upcomingQuotes.length,
itemBuilder: (BuildContext context, int index) {
return QuoteListItem(
@ -253,8 +248,7 @@ class QuoteSidebar extends StatelessWidget {
(expriedQuotes.isNotEmpty ? ' (${expriedQuotes.length})' : ''),
list2: expriedQuotes.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: expriedQuotes.length,
itemBuilder: (BuildContext context, int index) {
return QuoteListItem(
@ -269,8 +263,7 @@ class QuoteSidebar extends StatelessWidget {
: localization.selectedQuotes + ' (${selectedIds.length})',
list3: (selectedIds ?? <String>[]).isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: selectedIds?.length,
itemBuilder: (BuildContext context, int index) {
final quote = state.quoteState.map[selectedIds[index]];
@ -312,8 +305,7 @@ class TaskSidebar extends StatelessWidget {
(runningTasks.isNotEmpty ? ' (${runningTasks.length})' : ''),
list1: runningTasks.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: runningTasks.length,
itemBuilder: (BuildContext context, int index) {
return TaskListItem(
@ -327,8 +319,7 @@ class TaskSidebar extends StatelessWidget {
(recentTasks.isNotEmpty ? ' (${recentTasks.length})' : ''),
list2: recentTasks.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: recentTasks.length,
itemBuilder: (BuildContext context, int index) {
return TaskListItem(
@ -343,8 +334,7 @@ class TaskSidebar extends StatelessWidget {
: localization.selectedTasks + ' (${selectedIds.length})',
list3: (selectedIds ?? <String>[]).isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: selectedIds?.length,
itemBuilder: (BuildContext context, int index) {
final task = state.taskState.map[selectedIds[index]];
@ -390,8 +380,7 @@ class ExpenseSidbar extends StatelessWidget {
(upcomingExpenses.isNotEmpty ? ' (${upcomingExpenses.length})' : ''),
list1: upcomingExpenses.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: upcomingExpenses.length,
itemBuilder: (BuildContext context, int index) {
return ExpenseListItem(
@ -406,8 +395,7 @@ class ExpenseSidbar extends StatelessWidget {
(recentExpenses.isNotEmpty ? ' (${recentExpenses.length})' : ''),
list1: recentExpenses.isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: recentExpenses.length,
itemBuilder: (BuildContext context, int index) {
return ExpenseListItem(
@ -422,8 +410,7 @@ class ExpenseSidbar extends StatelessWidget {
: localization.selectedExpenses + ' (${selectedIds.length})',
list3: (selectedIds ?? <String>[]).isEmpty
? null
: ListView.separated(
shrinkWrap: true,
: ScrollableListViewBuilder(
itemCount: selectedIds?.length,
itemBuilder: (BuildContext context, int index) {
final expense = state.expenseState.map[selectedIds[index]];
@ -455,9 +442,9 @@ class _DashboardSidebar extends StatelessWidget {
final String label1;
final String label2;
final String label3;
final ListView list1;
final ListView list2;
final ListView list3;
final ScrollableListViewBuilder list1;
final ScrollableListViewBuilder list2;
final ScrollableListViewBuilder list3;
@override
Widget build(BuildContext context) {

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/invoice/view/invoice_view_vm.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:timeago/timeago.dart' as timeago;
@ -37,8 +38,7 @@ class _InvoiceViewHistoryState extends State<InvoiceViewHistory> {
final historyList = invoice.history.toList();
historyList.sort((a, b) => b.createdAt.compareTo(a.createdAt));
return ListView.separated(
shrinkWrap: true,
return ScrollableListViewBuilder(
padding: const EdgeInsets.symmetric(vertical: 16),
itemBuilder: (BuildContext context, index) {
final history = historyList[index];

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/help_text.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/scrollable_listview.dart';
import 'package:invoiceninja_flutter/ui/app/tables/entity_datatable.dart';
import 'package:invoiceninja_flutter/ui/payment_term/payment_term_list_item.dart';
import 'package:invoiceninja_flutter/ui/payment_term/payment_term_list_vm.dart';
@ -38,7 +39,7 @@ class _PaymentTermListState extends State<PaymentTermList> {
return RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ListView.separated(
child: ScrollableListViewBuilder(
separatorBuilder: (context, index) => ListDivider(),
itemCount: viewModel.paymentTermList.length,
itemBuilder: (BuildContext context, index) {