invoice/lib/ui/app/entities/entity_list_tile.dart

239 lines
8.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/data/models/client_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/actions_menu_button.dart';
import 'package:invoiceninja_flutter/ui/app/entity_state_label.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/app/lists/selected_indicator.dart';
import 'package:invoiceninja_flutter/utils/icons.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:invoiceninja_flutter/utils/strings.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
class EntityListTile extends StatefulWidget {
const EntityListTile({
@required this.entity,
@required this.isFilter,
this.onEntityActionSelected,
this.subtitle,
this.client,
});
final String subtitle;
final BaseEntity entity;
final bool isFilter;
final ClientEntity client;
final Function(BuildContext, BaseEntity, EntityAction) onEntityActionSelected;
@override
_EntityListTileState createState() => _EntityListTileState();
}
class _EntityListTileState extends State<EntityListTile> {
bool _isHovered = false;
@override
Widget build(BuildContext context) {
if (widget.entity == null || widget.entity.isNew) {
return SizedBox();
}
final localization = AppLocalization.of(context);
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final isFilteredBy = state.uiState.filterEntityId == widget.entity.id &&
state.uiState.filterEntityType == widget.entity.entityType;
final entityClient = widget.client ??
(widget.entity is BelongsToClient
? state.clientState.map[(widget.entity as BelongsToClient).clientId]
: null);
final isHovered =
(!RendererBinding.instance.mouseTracker.mouseIsConnected &&
isFilteredBy) ||
_isHovered;
final leading = ActionMenuButton(
iconData:
isHovered ? Icons.more_vert : getEntityIcon(widget.entity.entityType),
iconSize: isHovered ? null : 18,
entityActions: widget.entity.getActions(
userCompany: state.userCompany,
includeEdit: true,
client: entityClient),
isSaving: false,
color: isFilteredBy
? (state.prefState.enableDarkMode
? Colors.white
: Theme.of(context).accentColor)
: null,
entity: widget.entity,
onSelected: (context, action) => widget.onEntityActionSelected != null
? widget.onEntityActionSelected(context, widget.entity, action)
: handleEntityAction(context, widget.entity, action),
);
final trailing = widget.isFilter
? SizedBox()
: IgnorePointer(
ignoring: !isHovered,
child: IconButton(
icon: Icon(isHovered ||
isMobile(context) ||
state.uiState.previewStack.isNotEmpty
? Icons.chevron_right
: Icons.filter_list),
onPressed: () => viewEntity(
entity: widget.entity,
context: context,
addToStack: isDesktop(context) && !widget.isFilter,
),
color: isFilteredBy
? (state.prefState.enableDarkMode
? Colors.white
: Theme.of(context).accentColor)
: null,
),
);
return MouseRegion(
onEnter: (event) => setState(() => _isHovered = true),
onExit: (event) => setState(() => _isHovered = false),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SelectedIndicator(
isSelected: isFilteredBy && isDesktop(context),
isMenu: true,
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
onTap: isDesktop(context) && widget.isFilter
? null
: () =>
inspectEntity(context: context, entity: widget.entity),
onLongPress: () => inspectEntity(
context: context, entity: widget.entity, longPress: true),
title: Text(
localization.lookup('${widget.entity.entityType}') +
' ' +
widget.entity.listDisplayName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle:
(widget.subtitle ?? '').isEmpty && widget.entity.isActive
? null
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if ((widget.subtitle ?? '').isNotEmpty)
Text(widget.subtitle),
if (!widget.entity.isActive)
EntityStateLabel(widget.entity),
],
),
leading: leading,
trailing: trailing,
isThreeLine:
(widget.subtitle ?? '').isNotEmpty && !widget.entity.isActive,
),
),
ListDivider(),
],
),
);
}
}
class EntitiesListTile extends StatefulWidget {
const EntitiesListTile({
@required this.isFilter,
@required this.entity,
this.entityType,
this.title,
this.subtitle,
this.hideNew = false,
});
final BaseEntity entity;
final EntityType entityType;
final String title;
final String subtitle;
final bool isFilter;
final bool hideNew;
@override
_EntitiesListTileState createState() => _EntitiesListTileState();
}
class _EntitiesListTileState extends State<EntitiesListTile> {
bool _isHovered = false;
void _onTap(BuildContext context) => viewEntitiesByType(
context: context,
entityType: widget.entityType,
filterEntity: widget.entity);
void _onLongPress() => handleEntityAction(
context, widget.entity, EntityAction.newEntityType(widget.entityType));
@override
Widget build(BuildContext context) {
final store = StoreProvider.of<AppState>(context);
final state = store.state;
final mainRoute = state.uiState.mainRoute;
final isFilterMatch =
widget.isFilter && '${widget.entityType}' == toCamelCase(mainRoute);
return MouseRegion(
onEnter: (event) => setState(() => _isHovered = true),
onExit: (event) => setState(() => _isHovered = false),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SelectedIndicator(
isSelected: isFilterMatch,
isMenu: true,
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
title: Text(widget.title),
subtitle: Text((widget.subtitle ?? '').isEmpty
? AppLocalization.of(context).none
: widget.subtitle),
leading: _isHovered && !widget.hideNew
? IconButton(
icon: Icon(Icons.add_circle_outline),
onPressed: _onLongPress,
)
: IgnorePointer(
child: IconButton(
icon:
Icon(getEntityIcon(widget.entityType), size: 18.0),
onPressed: () => _onTap(context),
),
),
trailing: widget.isFilter
? SizedBox()
: IgnorePointer(
child: IconButton(
icon: Icon(MdiIcons.chevronDoubleRight),
onPressed: () => null,
),
),
onTap: () => _onTap(context),
onLongPress: _onLongPress,
),
),
ListDivider(),
],
),
);
}
}