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';
|
||||
|
||||
class EntityTopFilter extends StatelessWidget {
|
||||
const EntityTopFilter({@required this.show});
|
||||
const EntityTopFilter({
|
||||
@required this.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/client/client_actions.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/client/view/client_view_activity.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) {
|
||||
final localization = AppLocalization.of(context);
|
||||
final store = StoreProvider.of<AppState>(context);
|
||||
final state = store.state;
|
||||
final viewModel = widget.viewModel;
|
||||
final client = viewModel.client;
|
||||
final documents = client.documents;
|
||||
final userCompany = viewModel.state.userCompany;
|
||||
|
||||
if (widget.isTopFilter) {
|
||||
return ViewScaffold(
|
||||
body: Placeholder(),
|
||||
entity: client,
|
||||
return Material(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
EntityBottomFilter(),
|
||||
Expanded(child: Placeholder()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue