Dashboard
This commit is contained in:
parent
52496d15ae
commit
01e291df56
|
|
@ -61,3 +61,36 @@ List<PaymentEntity> _recentPayments(
|
|||
|
||||
return payments;
|
||||
}
|
||||
|
||||
var memoizedUpcomingQuotes = memo1((BuiltMap<String, InvoiceEntity> quoteMap) =>
|
||||
_upcomingQuotes(quoteMap: quoteMap));
|
||||
|
||||
List<InvoiceEntity> _upcomingQuotes(
|
||||
{BuiltMap<String, InvoiceEntity> quoteMap}) {
|
||||
final quotes = <InvoiceEntity>[];
|
||||
quoteMap.forEach((index, quote) {
|
||||
if (quote.isUpcoming) {
|
||||
quotes.add(quote);
|
||||
}
|
||||
});
|
||||
|
||||
quotes.sort((quoteA, quoteB) => quoteA.dueDate.compareTo(quoteB.dueDate));
|
||||
|
||||
return quotes;
|
||||
}
|
||||
|
||||
var memoizedExpiredQuotes = memo1((BuiltMap<String, InvoiceEntity> quoteMap) =>
|
||||
_expiredQuotes(quoteMap: quoteMap));
|
||||
|
||||
List<InvoiceEntity> _expiredQuotes({BuiltMap<String, InvoiceEntity> quoteMap}) {
|
||||
final quotes = <InvoiceEntity>[];
|
||||
quoteMap.forEach((index, quote) {
|
||||
if (quote.isPastDue) {
|
||||
quotes.add(quote);
|
||||
}
|
||||
});
|
||||
|
||||
quotes.sort((quoteA, quoteB) => quoteA.dueDate.compareTo(quoteB.dueDate));
|
||||
|
||||
return quotes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,14 @@ abstract class QuoteState implements Built<QuoteState, QuoteStateBuilder> {
|
|||
|
||||
BuiltList<String> get list;
|
||||
|
||||
InvoiceEntity get(String quoteId) {
|
||||
if (map.containsKey(quoteId)) {
|
||||
return map[quoteId];
|
||||
} else {
|
||||
return InvoiceEntity(id: quoteId, entityType: EntityType.quote);
|
||||
}
|
||||
}
|
||||
|
||||
QuoteState loadQuotes(BuiltList<InvoiceEntity> quotes) {
|
||||
final map = Map<String, InvoiceEntity>.fromIterable(
|
||||
quotes,
|
||||
|
|
|
|||
|
|
@ -92,8 +92,10 @@ class DismissibleEntity extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
child: SelectedIndicator(
|
||||
isSelected:
|
||||
isSelected && !isMultiselect && !entity.entityType.isSetting,
|
||||
isSelected: isSelected &&
|
||||
showCheckbox &&
|
||||
!isMultiselect &&
|
||||
!entity.entityType.isSetting,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: 60,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import 'package:invoiceninja_flutter/ui/app/help_text.dart';
|
|||
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
|
||||
import 'package:invoiceninja_flutter/ui/invoice/invoice_list_item.dart';
|
||||
import 'package:invoiceninja_flutter/ui/payment/payment_list_item.dart';
|
||||
import 'package:invoiceninja_flutter/ui/quote/quote_list_item.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
|
||||
class SidebarScaffold extends StatelessWidget {
|
||||
|
|
@ -185,37 +186,37 @@ class _QuoteSidebar extends StatelessWidget {
|
|||
final localization = AppLocalization.of(context);
|
||||
final store = StoreProvider.of<AppState>(context);
|
||||
final state = store.state;
|
||||
final upcomingInvoices = memoizedUpcomingInvoices(state.invoiceState.map);
|
||||
final pastDueInvoices = memoizedPastDueInvoices(state.invoiceState.map);
|
||||
final selectedIds = state.uiState.selectedEntities[EntityType.invoice];
|
||||
final upcomingQuotes = memoizedUpcomingQuotes(state.quoteState.map);
|
||||
final expriedQuotes = memoizedExpiredQuotes(state.quoteState.map);
|
||||
final selectedIds = state.uiState.selectedEntities[EntityType.quote];
|
||||
|
||||
return _DashboardSidebar(
|
||||
entityType: EntityType.invoice,
|
||||
label1: localization.upcomingInvoices +
|
||||
(upcomingInvoices.isNotEmpty ? ' (${upcomingInvoices.length})' : ''),
|
||||
list1: upcomingInvoices.isEmpty
|
||||
entityType: EntityType.quote,
|
||||
label1: localization.upcomingQuotes +
|
||||
(upcomingQuotes.isNotEmpty ? ' (${upcomingQuotes.length})' : ''),
|
||||
list1: upcomingQuotes.isEmpty
|
||||
? null
|
||||
: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: upcomingInvoices.length,
|
||||
itemCount: upcomingQuotes.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return InvoiceListItem(
|
||||
invoice: upcomingInvoices[index],
|
||||
return QuoteListItem(
|
||||
quote: upcomingQuotes[index],
|
||||
showCheckbox: false,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => ListDivider(),
|
||||
),
|
||||
label2: localization.pastDueInvoices +
|
||||
(pastDueInvoices.isNotEmpty ? ' (${pastDueInvoices.length})' : ''),
|
||||
list2: pastDueInvoices.isEmpty
|
||||
(expriedQuotes.isNotEmpty ? ' (${expriedQuotes.length})' : ''),
|
||||
list2: expriedQuotes.isEmpty
|
||||
? null
|
||||
: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: pastDueInvoices.length,
|
||||
itemCount: expriedQuotes.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return InvoiceListItem(
|
||||
invoice: pastDueInvoices[index],
|
||||
return QuoteListItem(
|
||||
quote: expriedQuotes[index],
|
||||
showCheckbox: false,
|
||||
);
|
||||
},
|
||||
|
|
@ -230,8 +231,8 @@ class _QuoteSidebar extends StatelessWidget {
|
|||
shrinkWrap: true,
|
||||
itemCount: selectedIds?.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return InvoiceListItem(
|
||||
invoice: state.invoiceState.get(selectedIds[index]),
|
||||
return QuoteListItem(
|
||||
quote: state.quoteState.get(selectedIds[index]),
|
||||
showCheckbox: false,
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ class InvoiceListItem extends StatelessWidget {
|
|||
|
||||
return DismissibleEntity(
|
||||
isSelected: isDesktop(context) &&
|
||||
showCheckbox &&
|
||||
invoice.id ==
|
||||
(uiState.isEditing
|
||||
? invoiceUIState.editing.id
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ class PaymentListItem extends StatelessWidget {
|
|||
|
||||
return DismissibleEntity(
|
||||
isSelected: isDesktop(context) &&
|
||||
showCheckbox &&
|
||||
payment.id ==
|
||||
(uiState.isEditing
|
||||
? paymentUIState.editing.id
|
||||
|
|
|
|||
|
|
@ -14,33 +14,24 @@ import 'package:invoiceninja_flutter/utils/localization.dart';
|
|||
|
||||
class QuoteListItem extends StatelessWidget {
|
||||
const QuoteListItem({
|
||||
@required this.user,
|
||||
@required this.quote,
|
||||
@required this.client,
|
||||
@required this.filter,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.onCheckboxChanged,
|
||||
this.isChecked = false,
|
||||
this.filter,
|
||||
this.showCheckbox = true,
|
||||
});
|
||||
|
||||
final UserEntity user;
|
||||
final GestureTapCallback onTap;
|
||||
final GestureTapCallback onLongPress;
|
||||
final InvoiceEntity quote;
|
||||
final ClientEntity client;
|
||||
final String filter;
|
||||
final Function(bool) onCheckboxChanged;
|
||||
final bool isChecked;
|
||||
final bool showCheckbox;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final state = StoreProvider.of<AppState>(context).state;
|
||||
final client = state.clientState.get(quote.clientId);
|
||||
final uiState = state.uiState;
|
||||
final quoteUIState = uiState.quoteUIState;
|
||||
final listUIState = state.getUIState(quote.entityType).listUIState;
|
||||
final isInMultiselect = listUIState.isInMultiselect();
|
||||
final showCheckbox = onCheckboxChanged != null || isInMultiselect;
|
||||
final isInMultiselect = showCheckbox && listUIState.isInMultiselect();
|
||||
final isChecked = isInMultiselect && listUIState.isSelected(quote.id);
|
||||
final textStyle = TextStyle(fontSize: 16);
|
||||
final localization = AppLocalization.of(context);
|
||||
final textColor = Theme.of(context).textTheme.bodyText1.color;
|
||||
|
|
@ -66,17 +57,14 @@ class QuoteListItem extends StatelessWidget {
|
|||
? quoteUIState.editing.id
|
||||
: quoteUIState.selectedId),
|
||||
userCompany: state.userCompany,
|
||||
showCheckbox: showCheckbox,
|
||||
entity: quote,
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return constraints.maxWidth > kTableListWidthCutoff
|
||||
? InkWell(
|
||||
onTap: () => onTap != null
|
||||
? onTap()
|
||||
: selectEntity(entity: quote, context: context),
|
||||
onLongPress: () => onLongPress != null
|
||||
? onLongPress()
|
||||
: selectEntity(
|
||||
onTap: () => selectEntity(entity: quote, context: context),
|
||||
onLongPress: () => selectEntity(
|
||||
entity: quote, context: context, longPress: true),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
|
|
@ -96,8 +84,7 @@ class QuoteListItem extends StatelessWidget {
|
|||
value: isChecked,
|
||||
materialTapTargetSize:
|
||||
MaterialTapTargetSize.shrinkWrap,
|
||||
onChanged: (value) =>
|
||||
onCheckboxChanged(value),
|
||||
onChanged: (value) => null,
|
||||
activeColor:
|
||||
Theme.of(context).accentColor,
|
||||
),
|
||||
|
|
@ -170,12 +157,8 @@ class QuoteListItem extends StatelessWidget {
|
|||
),
|
||||
)
|
||||
: ListTile(
|
||||
onTap: () => onTap != null
|
||||
? onTap()
|
||||
: selectEntity(entity: quote, context: context),
|
||||
onLongPress: () => onLongPress != null
|
||||
? onLongPress()
|
||||
: selectEntity(
|
||||
onTap: () => selectEntity(entity: quote, context: context),
|
||||
onLongPress: () => selectEntity(
|
||||
entity: quote, context: context, longPress: true),
|
||||
leading: showCheckbox
|
||||
? IgnorePointer(
|
||||
|
|
@ -184,7 +167,7 @@ class QuoteListItem extends StatelessWidget {
|
|||
value: isChecked,
|
||||
materialTapTargetSize:
|
||||
MaterialTapTargetSize.shrinkWrap,
|
||||
onChanged: (value) => onCheckboxChanged(value),
|
||||
onChanged: (value) => null,
|
||||
activeColor: Theme.of(context).accentColor,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ class QuoteListBuilder extends StatelessWidget {
|
|||
return StoreConnector<AppState, QuoteListVM>(
|
||||
converter: QuoteListVM.fromStore,
|
||||
builder: (context, viewModel) {
|
||||
final state = viewModel.state;
|
||||
return EntityList(
|
||||
entityType: EntityType.quote,
|
||||
presenter: QuotePresenter(),
|
||||
|
|
@ -41,15 +40,10 @@ class QuoteListBuilder extends StatelessWidget {
|
|||
itemBuilder: (BuildContext context, index) {
|
||||
final invoiceId = viewModel.invoiceList[index];
|
||||
final invoice = viewModel.invoiceMap[invoiceId];
|
||||
final listState = state.getListState(EntityType.quote);
|
||||
final isInMultiselect = listState.isInMultiselect();
|
||||
|
||||
return QuoteListItem(
|
||||
user: state.user,
|
||||
filter: viewModel.filter,
|
||||
quote: invoice,
|
||||
client: viewModel.clientMap[invoice.clientId] ?? ClientEntity(),
|
||||
isChecked: isInMultiselect && listState.isSelected(invoice.id),
|
||||
);
|
||||
});
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue