Client activity
This commit is contained in:
parent
968b560533
commit
a5208884cb
|
|
@ -0,0 +1,83 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:invoiceninja_flutter/data/models/entities.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
|
|
||||||
|
class ActivityListTile extends StatelessWidget {
|
||||||
|
const ActivityListTile({
|
||||||
|
Key key,
|
||||||
|
@required this.activity,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final ActivityEntity activity;
|
||||||
|
|
||||||
|
IconData getIconData(EntityType entityType) {
|
||||||
|
switch (entityType) {
|
||||||
|
case EntityType.client:
|
||||||
|
return FontAwesomeIcons.users;
|
||||||
|
case EntityType.invoice:
|
||||||
|
return FontAwesomeIcons.filePdfO;
|
||||||
|
case EntityType.payment:
|
||||||
|
return FontAwesomeIcons.creditCard;
|
||||||
|
case EntityType.credit:
|
||||||
|
return FontAwesomeIcons.creditCard;
|
||||||
|
case EntityType.quote:
|
||||||
|
return FontAwesomeIcons.fileAltO;
|
||||||
|
case EntityType.vendor:
|
||||||
|
return FontAwesomeIcons.building;
|
||||||
|
case EntityType.expense:
|
||||||
|
return FontAwesomeIcons.fileImageO;
|
||||||
|
case EntityType.task:
|
||||||
|
return FontAwesomeIcons.clockO;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final localization = AppLocalization.of(context);
|
||||||
|
final store = StoreProvider.of<AppState>(context);
|
||||||
|
final state = store.state;
|
||||||
|
|
||||||
|
String title = localization.lookup('activity_${activity.activityTypeId}');
|
||||||
|
title = activity.getDescription(
|
||||||
|
title,
|
||||||
|
user: state.selectedCompany.userMap[activity.userId],
|
||||||
|
client: state.clientState.map[activity.clientId],
|
||||||
|
invoice: state.invoiceState.map[activity.invoiceId],
|
||||||
|
);
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
leading: Icon(getIconData(activity.entityType)),
|
||||||
|
title: Text(title),
|
||||||
|
onTap: () {
|
||||||
|
switch (activity.entityType) {
|
||||||
|
case EntityType.client:
|
||||||
|
store.dispatch(
|
||||||
|
ViewClient(clientId: activity.clientId, context: context));
|
||||||
|
break;
|
||||||
|
case EntityType.invoice:
|
||||||
|
store.dispatch(
|
||||||
|
ViewInvoice(invoiceId: activity.invoiceId, context: context));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trailing: Icon(Icons.navigate_next),
|
||||||
|
subtitle: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Text(formatDate(
|
||||||
|
convertTimestampToSqlDate(activity.updatedAt), context,
|
||||||
|
showTime: true)),
|
||||||
|
SizedBox(width: 10.0),
|
||||||
|
(activity.isSystem ?? false) ? Icon(FontAwesomeIcons.server) : Container(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -53,7 +53,9 @@ class _ClientViewState extends State<ClientView>
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Theme.of(context).backgroundColor,
|
backgroundColor: Theme
|
||||||
|
.of(context)
|
||||||
|
.backgroundColor,
|
||||||
appBar: _CustomAppBar(
|
appBar: _CustomAppBar(
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
|
@ -63,7 +65,9 @@ class _ClientViewState extends State<ClientView>
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
backgroundColor: Theme.of(context).primaryColorDark,
|
backgroundColor: Theme
|
||||||
|
.of(context)
|
||||||
|
.primaryColorDark,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog<SimpleDialog>(
|
showDialog<SimpleDialog>(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
@ -148,7 +152,9 @@ class _CustomTabBarViewState extends State<CustomTabBarView> {
|
||||||
|
|
||||||
void _onTabChange() {
|
void _onTabChange() {
|
||||||
final viewModel = widget.viewModel;
|
final viewModel = widget.viewModel;
|
||||||
if (widget.controller.index == 2 && viewModel.client.activities.isEmpty) {
|
|
||||||
|
if (widget.controller.index == 2 && viewModel.client.activities.isEmpty &&
|
||||||
|
!viewModel.isLoading) {
|
||||||
viewModel.onRefreshed(context);
|
viewModel.onRefreshed(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -196,7 +202,7 @@ class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
|
|
||||||
return AppBar(
|
return AppBar(
|
||||||
title:
|
title:
|
||||||
Text(client.displayName ?? ''), // Text(localizations.clientDetails),
|
Text(client.displayName ?? ''), // Text(localizations.clientDetails),
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
//isScrollable: true,
|
//isScrollable: true,
|
||||||
|
|
@ -215,16 +221,16 @@ class _CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
actions: client.isNew
|
actions: client.isNew
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
EditIconButton(
|
EditIconButton(
|
||||||
isVisible: !client.isDeleted,
|
isVisible: !client.isDeleted,
|
||||||
onPressed: () => viewModel.onEditPressed(context),
|
onPressed: () => viewModel.onEditPressed(context),
|
||||||
),
|
),
|
||||||
ActionMenuButton(
|
ActionMenuButton(
|
||||||
isSaving: viewModel.isSaving,
|
isSaving: viewModel.isSaving,
|
||||||
entity: client,
|
entity: client,
|
||||||
onSelected: viewModel.onActionSelected,
|
onSelected: viewModel.onActionSelected,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:invoiceninja_flutter/data/models/client_model.dart';
|
import 'package:invoiceninja_flutter/data/models/client_model.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/app/lists/activity_list_tile.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
||||||
|
|
||||||
class ClientViewActivity extends StatelessWidget {
|
class ClientViewActivity extends StatelessWidget {
|
||||||
|
|
@ -20,8 +21,7 @@ class ClientViewActivity extends StatelessWidget {
|
||||||
itemCount: activities.length,
|
itemCount: activities.length,
|
||||||
itemBuilder: (BuildContext context, index) {
|
itemBuilder: (BuildContext context, index) {
|
||||||
final activity = activities[index];
|
final activity = activities[index];
|
||||||
return Text(activity.key);
|
return ActivityListTile(activity: activity);
|
||||||
//return ActivityListTile(activity: activity);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ class ClientViewVM {
|
||||||
final Function(BuildContext) onInvoicesPressed;
|
final Function(BuildContext) onInvoicesPressed;
|
||||||
final Function(BuildContext) onRefreshed;
|
final Function(BuildContext) onRefreshed;
|
||||||
final bool isSaving;
|
final bool isSaving;
|
||||||
|
final bool isLoading;
|
||||||
final bool isDirty;
|
final bool isDirty;
|
||||||
|
|
||||||
ClientViewVM({
|
ClientViewVM({
|
||||||
|
|
@ -52,6 +53,7 @@ class ClientViewVM {
|
||||||
@required this.onInvoicesPressed,
|
@required this.onInvoicesPressed,
|
||||||
@required this.onBackPressed,
|
@required this.onBackPressed,
|
||||||
@required this.isSaving,
|
@required this.isSaving,
|
||||||
|
@required this.isLoading,
|
||||||
@required this.isDirty,
|
@required this.isDirty,
|
||||||
@required this.onRefreshed,
|
@required this.onRefreshed,
|
||||||
});
|
});
|
||||||
|
|
@ -73,6 +75,7 @@ class ClientViewVM {
|
||||||
|
|
||||||
return ClientViewVM(
|
return ClientViewVM(
|
||||||
isSaving: state.isSaving,
|
isSaving: state.isSaving,
|
||||||
|
isLoading: state.isLoading,
|
||||||
isDirty: client.isNew,
|
isDirty: client.isNew,
|
||||||
client: client,
|
client: client,
|
||||||
company: state.selectedCompany,
|
company: state.selectedCompany,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:invoiceninja_flutter/ui/app/lists/activity_list_tile.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
||||||
import 'package:invoiceninja_flutter/data/models/entities.dart';
|
|
||||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
|
||||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
|
||||||
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
|
|
||||||
import 'package:invoiceninja_flutter/redux/invoice/invoice_actions.dart';
|
|
||||||
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/dashboard/dashboard_vm.dart';
|
import 'package:invoiceninja_flutter/ui/dashboard/dashboard_vm.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
|
||||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
|
||||||
|
|
||||||
class DashboardActivity extends StatelessWidget {
|
class DashboardActivity extends StatelessWidget {
|
||||||
const DashboardActivity({
|
const DashboardActivity({
|
||||||
|
|
@ -37,76 +29,3 @@ class DashboardActivity extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActivityListTile extends StatelessWidget {
|
|
||||||
const ActivityListTile({
|
|
||||||
Key key,
|
|
||||||
@required this.activity,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final ActivityEntity activity;
|
|
||||||
|
|
||||||
IconData getIconData(EntityType entityType) {
|
|
||||||
switch (entityType) {
|
|
||||||
case EntityType.client:
|
|
||||||
return FontAwesomeIcons.users;
|
|
||||||
case EntityType.invoice:
|
|
||||||
return FontAwesomeIcons.filePdfO;
|
|
||||||
case EntityType.payment:
|
|
||||||
return FontAwesomeIcons.creditCard;
|
|
||||||
case EntityType.credit:
|
|
||||||
return FontAwesomeIcons.creditCard;
|
|
||||||
case EntityType.quote:
|
|
||||||
return FontAwesomeIcons.fileAltO;
|
|
||||||
case EntityType.vendor:
|
|
||||||
return FontAwesomeIcons.building;
|
|
||||||
case EntityType.expense:
|
|
||||||
return FontAwesomeIcons.fileImageO;
|
|
||||||
case EntityType.task:
|
|
||||||
return FontAwesomeIcons.clockO;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final localization = AppLocalization.of(context);
|
|
||||||
final store = StoreProvider.of<AppState>(context);
|
|
||||||
final state = store.state;
|
|
||||||
|
|
||||||
String title = localization.lookup('activity_${activity.activityTypeId}');
|
|
||||||
title = activity.getDescription(
|
|
||||||
title,
|
|
||||||
user: state.selectedCompany.userMap[activity.userId],
|
|
||||||
client: state.clientState.map[activity.clientId],
|
|
||||||
invoice: state.invoiceState.map[activity.invoiceId],
|
|
||||||
);
|
|
||||||
|
|
||||||
return ListTile(
|
|
||||||
leading: Icon(getIconData(activity.entityType)),
|
|
||||||
title: Text(title),
|
|
||||||
onTap: () {
|
|
||||||
switch (activity.entityType) {
|
|
||||||
case EntityType.client:
|
|
||||||
store.dispatch(
|
|
||||||
ViewClient(clientId: activity.clientId, context: context));
|
|
||||||
break;
|
|
||||||
case EntityType.invoice:
|
|
||||||
store.dispatch(
|
|
||||||
ViewInvoice(invoiceId: activity.invoiceId, context: context));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
trailing: Icon(Icons.navigate_next),
|
|
||||||
subtitle: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Text(formatDate(
|
|
||||||
convertTimestampToSqlDate(activity.updatedAt), context,
|
|
||||||
showTime: true)),
|
|
||||||
SizedBox(width: 10.0),
|
|
||||||
(activity.isSystem ?? false) ? Icon(FontAwesomeIcons.server) : Container(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,6 @@ String formatDate(String value, BuildContext context, {bool showTime = false}) {
|
||||||
? company.datetimeFormatId
|
? company.datetimeFormatId
|
||||||
: kDefaultDateTimeFormat;
|
: kDefaultDateTimeFormat;
|
||||||
final formatter = DateFormat(dateTimeFormats[dateTimeFormatId].format);
|
final formatter = DateFormat(dateTimeFormats[dateTimeFormatId].format);
|
||||||
print(DateTime.tryParse(value).timeZoneName);
|
|
||||||
return formatter.format(DateTime.tryParse(value).toLocal());
|
return formatter.format(DateTime.tryParse(value).toLocal());
|
||||||
} else {
|
} else {
|
||||||
final dateFormats = state.staticState.dateFormatMap;
|
final dateFormats = state.staticState.dateFormatMap;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue