This commit is contained in:
Hillel Coren 2018-12-17 17:10:39 +02:00
parent ec23625c60
commit 251617d0d7
4 changed files with 239 additions and 110 deletions

View File

@ -14,30 +14,11 @@ class ProjectList extends StatelessWidget {
@required this.viewModel,
}) : super(key: key);
@override
Widget build(BuildContext context) {
if (!viewModel.isLoaded) {
return LoadingIndicator();
} else if (viewModel.projectList.isEmpty) {
return Opacity(
opacity: 0.5,
child: Center(
child: Text(
AppLocalization.of(context).noRecordsFound,
style: TextStyle(
fontSize: 18.0,
),
),
),
);
}
return _buildListView(context);
}
final ProjectListVM viewModel;
void _showMenu(
BuildContext context, ProjectEntity project) async {
if (project == null) {
BuildContext context, ProjectEntity project, ClientEntity client) async {
if (project == null || client == null) {
return;
}
@ -46,7 +27,7 @@ class ProjectList extends StatelessWidget {
context: context,
builder: (BuildContext dialogContext) => SimpleDialog(
children: project
.getEntityActions(user: user)
.getEntityActions(user: user, client: client)
.map((entityAction) {
if (entityAction == null) {
return Divider();
@ -71,37 +52,104 @@ class ProjectList extends StatelessWidget {
}
}
Widget _buildListView(BuildContext context) {
return RefreshIndicator(
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
final listState = viewModel.listState;
final filteredClientId = listState.filterEntityId;
final filteredClient =
filteredClientId != null ? viewModel.clientMap[filteredClientId] : null;
return Column(
children: <Widget>[
filteredClient != null
? Material(
color: Colors.orangeAccent,
elevation: 6.0,
child: InkWell(
onTap: () => viewModel.onViewEntityFilterPressed(context),
child: Row(
children: <Widget>[
SizedBox(width: 18.0),
Expanded(
child: Text(
'${localization.filteredBy} ${filteredClient.listDisplayName}',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
),
),
),
IconButton(
icon: Icon(
Icons.close,
color: Colors.white,
),
onPressed: () => viewModel.onClearEntityFilterPressed(),
)
],
),
),
)
: Container(),
Expanded(
child: !viewModel.isLoaded
? LoadingIndicator()
: RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ListView.builder(
child: viewModel.projectList.isEmpty
? Opacity(
opacity: 0.5,
child: Center(
child: Text(
AppLocalization.of(context).noRecordsFound,
style: TextStyle(
fontSize: 18.0,
),
),
),
)
: ListView.builder(
shrinkWrap: true,
itemCount: viewModel.projectList.length,
itemBuilder: (BuildContext context, index) {
final projectId = viewModel.projectList[index];
final project = viewModel.projectMap[projectId];
return Column(children: <Widget>[
final client =
viewModel.clientMap[project.clientId] ??
ClientEntity();
return Column(
children: <Widget>[
ProjectListItem(
user: viewModel.user,
filter: viewModel.filter,
project: project,
client: viewModel.clientMap[project.clientId],
client:
viewModel.clientMap[project.clientId] ??
ClientEntity(),
onTap: () =>
viewModel.onProjectTap(context, project),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
_showMenu(context, project);
_showMenu(context, project, client);
} else {
viewModel.onEntityAction(context, project, action);
viewModel.onEntityAction(
context, project, action);
}
},
onTap: () => viewModel.onProjectTap(context, project),
onLongPress: () => _showMenu(context, project),
onLongPress: () =>
_showMenu(context, project, client),
),
Divider(
height: 1.0,
),
]);
}),
],
);
},
),
),
),
],
);
}
final ProjectListVM viewModel;
}

View File

@ -1,4 +1,6 @@
import 'dart:async';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:redux/redux.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
@ -35,12 +37,15 @@ class ProjectListVM {
@required this.projectList,
@required this.projectMap,
@required this.clientMap,
@required this.listState,
@required this.filter,
@required this.isLoading,
@required this.isLoaded,
@required this.onProjectTap,
@required this.onRefreshed,
@required this.onEntityAction,
@required this.onClearEntityFilterPressed,
@required this.onViewEntityFilterPressed,
});
static ProjectListVM fromStore(Store<AppState> store) {
@ -58,6 +63,7 @@ class ProjectListVM {
return ProjectListVM(
user: state.user,
listState: state.projectListState,
projectList: memoizedFilteredProjectList(state.projectState.map,
state.projectState.list, state.projectListState, state.clientState.map),
projectMap: state.projectState.map,
@ -65,6 +71,12 @@ class ProjectListVM {
isLoading: state.isLoading,
isLoaded: state.projectState.isLoaded,
filter: state.projectUIState.listUIState.filter,
onClearEntityFilterPressed: () =>
store.dispatch(FilterProjectsByEntity()),
onViewEntityFilterPressed: (BuildContext context) => store.dispatch(
ViewClient(
clientId: state.invoiceListState.filterEntityId,
context: context)),
onProjectTap: (context, project) {
store.dispatch(ViewProject(projectId: project.id, context: context));
},
@ -103,10 +115,14 @@ class ProjectListVM {
final List<int> projectList;
final BuiltMap<int, ProjectEntity> projectMap;
final BuiltMap<int, ClientEntity> clientMap;
final ListUIState listState;
final String filter;
final bool isLoading;
final bool isLoaded;
final Function(BuildContext, ProjectEntity) onProjectTap;
final Function(BuildContext) onRefreshed;
final Function(BuildContext, ProjectEntity, EntityAction) onEntityAction;
final Function onClearEntityFilterPressed;
final Function(BuildContext) onViewEntityFilterPressed;
}

View File

@ -14,30 +14,11 @@ class StubList extends StatelessWidget {
@required this.viewModel,
}) : super(key: key);
@override
Widget build(BuildContext context) {
if (!viewModel.isLoaded) {
return LoadingIndicator();
} else if (viewModel.stubList.isEmpty) {
return Opacity(
opacity: 0.5,
child: Center(
child: Text(
AppLocalization.of(context).noRecordsFound,
style: TextStyle(
fontSize: 18.0,
),
),
),
);
}
return _buildListView(context);
}
final StubListVM viewModel;
void _showMenu(
BuildContext context, StubEntity stub) async {
if (stub == null) {
BuildContext context, StubEntity stub, ClientEntity client) async {
if (stub == null || client == null) {
return;
}
@ -46,7 +27,7 @@ class StubList extends StatelessWidget {
context: context,
builder: (BuildContext dialogContext) => SimpleDialog(
children: stub
.getEntityActions(user: user)
.getEntityActions(user: user, client: client)
.map((entityAction) {
if (entityAction == null) {
return Divider();
@ -71,36 +52,104 @@ class StubList extends StatelessWidget {
}
}
Widget _buildListView(BuildContext context) {
return RefreshIndicator(
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
final listState = viewModel.listState;
final filteredClientId = listState.filterEntityId;
final filteredClient =
filteredClientId != null ? viewModel.clientMap[filteredClientId] : null;
return Column(
children: <Widget>[
filteredClient != null
? Material(
color: Colors.orangeAccent,
elevation: 6.0,
child: InkWell(
onTap: () => viewModel.onViewEntityFilterPressed(context),
child: Row(
children: <Widget>[
SizedBox(width: 18.0),
Expanded(
child: Text(
'${localization.filteredBy} ${filteredClient.listDisplayName}',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
),
),
),
IconButton(
icon: Icon(
Icons.close,
color: Colors.white,
),
onPressed: () => viewModel.onClearEntityFilterPressed(),
)
],
),
),
)
: Container(),
Expanded(
child: !viewModel.isLoaded
? LoadingIndicator()
: RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: ListView.builder(
child: viewModel.stubList.isEmpty
? Opacity(
opacity: 0.5,
child: Center(
child: Text(
AppLocalization.of(context).noRecordsFound,
style: TextStyle(
fontSize: 18.0,
),
),
),
)
: ListView.builder(
shrinkWrap: true,
itemCount: viewModel.stubList.length,
itemBuilder: (BuildContext context, index) {
final stubId = viewModel.stubList[index];
final stub = viewModel.stubMap[stubId];
return Column(children: <Widget>[
final client =
viewModel.clientMap[stub.clientId] ??
ClientEntity();
return Column(
children: <Widget>[
StubListItem(
user: viewModel.user,
filter: viewModel.filter,
stub: stub,
client:
viewModel.clientMap[stub.clientId] ??
ClientEntity(),
onTap: () =>
viewModel.onStubTap(context, stub),
onEntityAction: (EntityAction action) {
if (action == EntityAction.more) {
_showMenu(context, stub);
_showMenu(context, stub, client);
} else {
viewModel.onEntityAction(context, stub, action);
viewModel.onEntityAction(
context, stub, action);
}
},
onTap: () => viewModel.onStubTap(context, stub),
onLongPress: () => _showMenu(context, stub),
onLongPress: () =>
_showMenu(context, stub, client),
),
Divider(
height: 1.0,
),
]);
}),
],
);
},
),
),
),
],
);
}
final StubListVM viewModel;
}

View File

@ -5,6 +5,8 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:built_collection/built_collection.dart';
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/redux/stub/stub_selectors.dart';
@ -38,8 +40,11 @@ class StubListVM {
@required this.isLoading,
@required this.isLoaded,
@required this.onStubTap,
@required this.listState,
@required this.onRefreshed,
@required this.onEntityAction,
@required this.onClearEntityFilterPressed,
@required this.onViewEntityFilterPressed,
});
static StubListVM fromStore(Store<AppState> store) {
@ -57,12 +62,19 @@ class StubListVM {
return StubListVM(
user: state.user,
listState: state.stubListState,
stubList: memoizedFilteredStubList(state.stubState.map,
state.stubState.list, state.stubListState),
stubMap: state.stubState.map,
isLoading: state.isLoading,
isLoaded: state.stubState.isLoaded,
filter: state.stubUIState.listUIState.filter,
onClearEntityFilterPressed: () =>
store.dispatch(FilterStubsByEntity()),
onViewEntityFilterPressed: (BuildContext context) => store.dispatch(
ViewClient(
clientId: state.stubListState.filterEntityId,
context: context)),
onStubTap: (context, stub) {
store.dispatch(EditStub(stub: stub, context: context));
},
@ -100,10 +112,14 @@ class StubListVM {
final UserEntity user;
final List<int> stubList;
final BuiltMap<int, StubEntity> stubMap;
final ListUIState listState;
final String filter;
final bool isLoading;
final bool isLoaded;
final Function(BuildContext, StubEntity) onStubTap;
final Function(BuildContext) onRefreshed;
final Function(BuildContext, StubEntity, EntityAction) onEntityAction;
final Function onClearEntityFilterPressed;
final Function(BuildContext) onViewEntityFilterPressed;
}