Implement desktop client layout
This commit is contained in:
parent
d38307d902
commit
c46aadf4b9
|
|
@ -15,7 +15,9 @@ import 'package:invoiceninja_flutter/ui/app/presenters/entity_presenter.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
|
|
||||||
class EntityTopFilter extends StatelessWidget {
|
class EntityTopFilter extends StatelessWidget {
|
||||||
const EntityTopFilter({@required this.show});
|
const EntityTopFilter({
|
||||||
|
@required this.show,
|
||||||
|
});
|
||||||
|
|
||||||
final bool show;
|
final bool show;
|
||||||
|
|
||||||
|
|
@ -229,3 +231,181 @@ class EntityTopFilter extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EntityBottomFilter extends StatelessWidget {
|
||||||
|
const EntityBottomFilter();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final localization = AppLocalization.of(context);
|
||||||
|
final store = StoreProvider.of<AppState>(context);
|
||||||
|
final state = store.state;
|
||||||
|
final uiState = state.uiState;
|
||||||
|
final prefState = state.prefState;
|
||||||
|
|
||||||
|
final filterEntityType = uiState.filterEntityType;
|
||||||
|
final routeEntityType = uiState.entityTypeRoute;
|
||||||
|
|
||||||
|
final entityMap =
|
||||||
|
filterEntityType != null ? state.getEntityMap(filterEntityType) : null;
|
||||||
|
final filterEntity =
|
||||||
|
entityMap != null ? entityMap[uiState.filterEntityId] : null;
|
||||||
|
final relatedTypes = filterEntityType?.relatedTypes
|
||||||
|
?.where((element) => state.company.isModuleEnabled(element))
|
||||||
|
?.toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
final backgroundColor = !prefState.enableDarkMode && state.hasAccentColor
|
||||||
|
? state.accentColor
|
||||||
|
: Theme.of(context).cardColor;
|
||||||
|
|
||||||
|
return Material(
|
||||||
|
color: backgroundColor,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
if (!prefState.isFilterVisible)
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
store.dispatch(UpdateUserPreferences(
|
||||||
|
isFilterVisible: !prefState.isFilterVisible));
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
editEntity(context: context, entity: filterEntity);
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(width: 12),
|
||||||
|
Icon(
|
||||||
|
Icons.chrome_reader_mode,
|
||||||
|
color: state.headerTextColor,
|
||||||
|
),
|
||||||
|
SizedBox(width: 12),
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(maxWidth: 220),
|
||||||
|
child: Text(
|
||||||
|
EntityPresenter()
|
||||||
|
.initialize(filterEntity, context)
|
||||||
|
.title(),
|
||||||
|
style:
|
||||||
|
TextStyle(fontSize: 17, color: state.headerTextColor),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 12),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: OverflowView.flexible(
|
||||||
|
spacing: 4,
|
||||||
|
children: <Widget>[
|
||||||
|
for (int i = 0; i < relatedTypes.length; i++)
|
||||||
|
DecoratedBox(
|
||||||
|
child: TextButton(
|
||||||
|
child: Text(
|
||||||
|
localization.lookup('${relatedTypes[i].plural}'),
|
||||||
|
style: TextStyle(
|
||||||
|
color: state.headerTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
minimumSize: Size(0, 36),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
viewEntitiesByType(
|
||||||
|
entityType: relatedTypes[i],
|
||||||
|
filterEntity: filterEntity,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
handleEntityAction(filterEntity,
|
||||||
|
EntityAction.newEntityType(relatedTypes[i]));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: relatedTypes[i] == routeEntityType
|
||||||
|
? Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: prefState.enableDarkMode ||
|
||||||
|
!state.hasAccentColor
|
||||||
|
? state.accentColor
|
||||||
|
: Colors.white,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
builder: (context, remaining) {
|
||||||
|
return PopupMenuButton<EntityType>(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
localization.more,
|
||||||
|
style: TextStyle(color: state.headerTextColor),
|
||||||
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
Icon(Icons.arrow_drop_down,
|
||||||
|
color: state.headerTextColor),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
initialValue: routeEntityType,
|
||||||
|
onSelected: (EntityType value) {
|
||||||
|
if (value == filterEntityType) {
|
||||||
|
viewEntity(
|
||||||
|
entity: filterEntity,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
viewEntitiesByType(
|
||||||
|
entityType: value,
|
||||||
|
filterEntity: filterEntity,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (BuildContext context) => filterEntityType
|
||||||
|
.relatedTypes
|
||||||
|
.sublist(relatedTypes.length - remaining)
|
||||||
|
.where(
|
||||||
|
(element) => state.company.isModuleEnabled(element))
|
||||||
|
.map((type) => PopupMenuItem<EntityType>(
|
||||||
|
value: type,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 75,
|
||||||
|
),
|
||||||
|
child: Text(type == filterEntityType
|
||||||
|
? localization.overview
|
||||||
|
: '${localization.lookup(type.plural)}'),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.clear,
|
||||||
|
color: state.headerTextColor,
|
||||||
|
),
|
||||||
|
onPressed: () => store.dispatch(
|
||||||
|
FilterByEntity(entity: uiState.filterEntity),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
|
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/buttons/bottom_buttons.dart';
|
import 'package:invoiceninja_flutter/ui/app/buttons/bottom_buttons.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/app/entity_top_filter.dart';
|
||||||
|
import 'package:invoiceninja_flutter/ui/app/presenters/entity_presenter.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
|
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/client/view/client_view_activity.dart';
|
import 'package:invoiceninja_flutter/ui/client/view/client_view_activity.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/client/view/client_view_details.dart';
|
import 'package:invoiceninja_flutter/ui/client/view/client_view_details.dart';
|
||||||
|
|
@ -83,15 +85,22 @@ class _ClientViewState extends State<ClientView>
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final localization = AppLocalization.of(context);
|
final localization = AppLocalization.of(context);
|
||||||
final store = StoreProvider.of<AppState>(context);
|
final store = StoreProvider.of<AppState>(context);
|
||||||
|
final state = store.state;
|
||||||
final viewModel = widget.viewModel;
|
final viewModel = widget.viewModel;
|
||||||
final client = viewModel.client;
|
final client = viewModel.client;
|
||||||
final documents = client.documents;
|
final documents = client.documents;
|
||||||
final userCompany = viewModel.state.userCompany;
|
final userCompany = viewModel.state.userCompany;
|
||||||
|
|
||||||
if (widget.isTopFilter) {
|
if (widget.isTopFilter) {
|
||||||
return ViewScaffold(
|
return Material(
|
||||||
body: Placeholder(),
|
child: Column(
|
||||||
entity: client,
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
EntityBottomFilter(),
|
||||||
|
Expanded(child: Placeholder()),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue