Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
hillelcoren committed May 9, 2022
2 parents 920ab3b + af24ea5 commit 0dd1df3
Show file tree
Hide file tree
Showing 23 changed files with 447 additions and 224 deletions.
3 changes: 2 additions & 1 deletion lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class Constants {
}

// TODO remove version once #46609 is fixed
const String kClientVersion = '5.0.83';
const String kClientVersion = '5.0.84';
const String kMinServerVersion = '5.0.4';

const String kAppName = 'Invoice Ninja';
Expand Down Expand Up @@ -555,6 +555,7 @@ const String kDefaultLightSelectedColor = '#e5f5ff';
const String kDefaultLightBorderColor = '#dfdfdf';

const String kReportGroupDay = 'day';
const String kReportGroupWeek = 'week';
const String kReportGroupMonth = 'month';
const String kReportGroupYear = 'year';

Expand Down
3 changes: 3 additions & 0 deletions lib/data/models/expense_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ abstract class ExpenseEntity extends Object
shouldBeInvoiced &&
userCompany.canCreate(EntityType.invoice)) {
actions.add(EntityAction.invoiceExpense);
if ((clientId ?? '').isNotEmpty) {
actions.add(EntityAction.addToInvoice);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/data/models/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class EntityAction extends EnumClass {
static const EntityAction disconnect = _$disconnect;
static const EntityAction viewInvoice = _$viewInvoice;
static const EntityAction changeStatus = _$changeStatus;
static const EntityAction addToInvoice = _$addToInvoice;

@override
String toString() {
Expand Down
4 changes: 4 additions & 0 deletions lib/data/models/models.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions lib/data/models/task_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,9 @@ abstract class TaskEntity extends Object
if (!isInvoiced && !isRunning) {
if (userCompany.canCreate(EntityType.invoice)) {
actions.add(EntityAction.invoiceTask);
if ((clientId ?? '').isNotEmpty) {
actions.add(EntityAction.addToInvoice);
}
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions lib/redux/dashboard/dashboard_selectors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -807,3 +807,22 @@ var memoizedPreviousChartExpenses = memo5(
BuiltMap<String, InvoiceEntity> invoiceMap,
BuiltMap<String, ExpenseEntity> expenseMap) =>
chartExpenses(currencyMap, company, settings, invoiceMap, expenseMap));

var memoizedRunningTasks = memo2(
(BuiltMap<String, TaskEntity> taskMap, String userId) =>
runningTasks(taskMap, userId));

List<TaskEntity> runningTasks(
BuiltMap<String, TaskEntity> taskMap, String userId) {
final tasks = <TaskEntity>[];

taskMap.forEach((taskId, task) {
if (task.isRunning &&
!task.isDeleted &&
(task.createdUserId == userId || task.assignedUserId == userId)) {
tasks.add(task);
}
});

return tasks;
}
28 changes: 19 additions & 9 deletions lib/redux/expense/expense_actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
import 'package:invoiceninja_flutter/redux/expense/expense_selectors.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';

class ViewExpenseList implements PersistUI {
Expand Down Expand Up @@ -277,6 +278,7 @@ void handleExpenseAction(
);
break;
case EntityAction.invoiceExpense:
case EntityAction.addToInvoice:
final availableExpenses = expenses.where((entity) {
final expense = entity as ExpenseEntity;
return !expense.isDeleted && !expense.isInvoiced;
Expand Down Expand Up @@ -304,15 +306,23 @@ void handleExpenseAction(
))
.toList();
if (items.isNotEmpty) {
createEntity(
context: context,
entity: InvoiceEntity(state: state, client: client).rebuild(
(b) => b
..lineItems.addAll(items)
..projectId = projectId
..vendorId = vendorId,
),
);
if (action == EntityAction.invoiceExpense) {
createEntity(
context: context,
entity: InvoiceEntity(state: state, client: client).rebuild(
(b) => b
..lineItems.addAll(items)
..projectId = projectId
..vendorId = vendorId,
),
);
} else {
addToInvoiceDialog(
context: context,
clientId: expense.clientId,
items: items,
);
}
}
break;
case EntityAction.restore:
Expand Down
18 changes: 14 additions & 4 deletions lib/redux/task/task_actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ void handleTaskAction(
StopTasksRequest(snackBarCompleter<Null>(context, message), taskIds));
break;
case EntityAction.invoiceTask:
case EntityAction.addToInvoice:
tasks.sort((taskA, taskB) {
final taskAEntity = taskA as TaskEntity;
final taskBEntity = taskB as TaskEntity;
Expand Down Expand Up @@ -435,11 +436,20 @@ void handleTaskAction(
});

if (items.isNotEmpty) {
createEntity(
if (action == EntityAction.invoiceTask) {
createEntity(
context: context,
entity:
InvoiceEntity(state: state, client: client).rebuild((b) => b
..lineItems.addAll(items)
..projectId = projectId));
} else {
addToInvoiceDialog(
context: context,
entity: InvoiceEntity(state: state, client: client).rebuild((b) => b
..lineItems.addAll(items)
..projectId = projectId));
clientId: task.clientId,
items: items,
);
}
}
break;
case EntityAction.clone:
Expand Down
3 changes: 3 additions & 0 deletions lib/ui/app/tables/entity_datatable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ class EntityDataTableSource extends AppDataTableSource {
maxWidth: wideFields.contains(field)
? kTableColumnWidthMax * 1.5
: kTableColumnWidthMax,
minWidth: field == ProductFields.description
? kTableColumnWidthMax
: 0,
),
),
onTap: () => onTap(entity),
Expand Down
62 changes: 62 additions & 0 deletions lib/ui/dashboard/dashboard_panels.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import 'package:flutter/material.dart';
// Package imports:
import 'package:charts_common/common.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/task/task_actions.dart';
import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart';
import 'package:invoiceninja_flutter/ui/app/app_border.dart';
import 'package:invoiceninja_flutter/ui/app/live_text.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';

// Project imports:
Expand Down Expand Up @@ -407,7 +412,62 @@ class DashboardPanels extends StatelessWidget {
return LoadingIndicator();
}

final runningTasks =
memoizedRunningTasks(state.taskState.map, state.user.id);

Widget _runningTasks() {
return Padding(
padding: const EdgeInsets.only(top: 20, left: 12),
child: Wrap(
spacing: 8,
children: runningTasks.map((task) {
final client = state.clientState.map[task.clientId];
return Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(kBorderRadius),
),
child: AppBorder(
hideBorder: !isDarkMode(context),
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 180),
child: Tooltip(
message: task.description,
child: ListTile(
dense: true,
title: LiveText(() {
return formatDuration(task.calculateDuration());
}),
subtitle: Text(
client != null ? client.displayName : task.number,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
onTap: () =>
viewEntity(entity: task, filterEntity: client),
onLongPress: () =>
editEntity(context: context, entity: task),
leading: ActionMenuButton(
entity: task,
entityActions: task.getActions(
includeEdit: true,
userCompany: state.userCompany,
),
onSelected: (context, action) =>
handleTaskAction(context, [task], action),
),
),
),
),
),
);
}).toList()),
);
}

final entityTypes = [
if (company.isModuleEnabled(EntityType.task) && runningTasks.isNotEmpty)
EntityType.taskStatus,
if (company.isModuleEnabled(EntityType.invoice)) EntityType.invoice,
if (company.isModuleEnabled(EntityType.invoice)) EntityType.payment,
if (company.isModuleEnabled(EntityType.quote)) EntityType.quote,
Expand Down Expand Up @@ -456,6 +516,8 @@ class DashboardPanels extends StatelessWidget {
context: context,
onDateSelected: (entityIds) => viewModel
.onSelectionChanged(EntityType.expense, entityIds));
case EntityType.taskStatus:
return _runningTasks();
}

return SizedBox();
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/expense/edit/expense_edit_details.dart
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ class ExpenseEditDetailsState extends State<ExpenseEditDetails> {
projectId: expense.projectId,
clientId: expense.clientId,
onChanged: (selectedId) {
final project = state.projectState.get(selectedId);
final project = store.state.projectState.get(selectedId);
viewModel.onChanged(expense.rebuild((b) => b
..projectId = project?.id
..clientId = (project?.clientId ?? '').isNotEmpty
Expand Down
26 changes: 18 additions & 8 deletions lib/ui/invoice/edit/invoice_edit_desktop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,7 @@ class __PdfPreviewState extends State<_PdfPreview> {
String _pdfString;
http.Response _response;
bool _isLoading = false;
bool _pendingLoad = false;

@override
void didChangeDependencies() {
Expand Down Expand Up @@ -976,7 +977,12 @@ class __PdfPreviewState extends State<_PdfPreview> {
}

void _loadPdf() async {
if (!widget.invoice.hasClient || _isLoading) {
if (!widget.invoice.hasClient) {
return;
}

if (_isLoading) {
_pendingLoad = true;
return;
}

Expand Down Expand Up @@ -1017,6 +1023,11 @@ class __PdfPreviewState extends State<_PdfPreview> {
'data:application/pdf;base64,' + base64Encode(response.bodyBytes);
WebUtils.registerWebView(_pdfString);
}

if (_pendingLoad) {
_pendingLoad = false;
_loadPdf();
}
});
}).catchError((dynamic error) {
setState(() {
Expand All @@ -1039,7 +1050,7 @@ class __PdfPreviewState extends State<_PdfPreview> {
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (_pageCount > 1 && state.prefState.enableJSPDF)
if (_pageCount > 1 && (state.prefState.enableJSPDF || !kIsWeb))
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
Expand Down Expand Up @@ -1073,7 +1084,9 @@ class __PdfPreviewState extends State<_PdfPreview> {
),
Expanded(
child: _response == null
? SizedBox()
? Container(
color: Colors.grey.shade300,
)
: state.prefState.enableJSPDF || !kIsWeb
? PdfPreview(
build: (format) => _response.bodyBytes,
Expand All @@ -1088,11 +1101,8 @@ class __PdfPreviewState extends State<_PdfPreview> {
],
),
if (_isLoading)
Container(
color: Colors.grey.shade300,
child: Center(
child: CircularProgressIndicator(),
),
Center(
child: CircularProgressIndicator(),
)
],
),
Expand Down
Loading

0 comments on commit 0dd1df3

Please sign in to comment.