mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
Refactor table layout to accommodate dynamic table size
This commit is contained in:
@ -21,6 +21,7 @@ class DynamicTable extends StatefulWidget {
|
|||||||
final List<String>? initialSelectedIds;
|
final List<String>? initialSelectedIds;
|
||||||
final int uuidIndex;
|
final int uuidIndex;
|
||||||
final Function(dynamic selectedRows)? onSelectionChanged;
|
final Function(dynamic selectedRows)? onSelectionChanged;
|
||||||
|
final Function(int rowIndex)? onSettingsPressed;
|
||||||
const DynamicTable({
|
const DynamicTable({
|
||||||
super.key,
|
super.key,
|
||||||
required this.headers,
|
required this.headers,
|
||||||
@ -37,6 +38,7 @@ class DynamicTable extends StatefulWidget {
|
|||||||
this.initialSelectedIds,
|
this.initialSelectedIds,
|
||||||
required this.uuidIndex,
|
required this.uuidIndex,
|
||||||
this.onSelectionChanged,
|
this.onSelectionChanged,
|
||||||
|
this.onSettingsPressed,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -48,11 +50,20 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
bool _selectAll = false;
|
bool _selectAll = false;
|
||||||
final ScrollController _verticalScrollController = ScrollController();
|
final ScrollController _verticalScrollController = ScrollController();
|
||||||
final ScrollController _horizontalScrollController = ScrollController();
|
final ScrollController _horizontalScrollController = ScrollController();
|
||||||
|
late ScrollController _horizontalHeaderScrollController;
|
||||||
|
late ScrollController _horizontalBodyScrollController;
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_initializeSelection();
|
_initializeSelection();
|
||||||
|
_horizontalHeaderScrollController = ScrollController();
|
||||||
|
_horizontalBodyScrollController = ScrollController();
|
||||||
|
|
||||||
|
// Synchronize horizontal scrolling
|
||||||
|
_horizontalBodyScrollController.addListener(() {
|
||||||
|
_horizontalHeaderScrollController
|
||||||
|
.jumpTo(_horizontalBodyScrollController.offset);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -102,101 +113,87 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
context.read<DeviceManagementBloc>().add(UpdateSelection(_selectedRows));
|
context.read<DeviceManagementBloc>().add(UpdateSelection(_selectedRows));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_horizontalHeaderScrollController.dispose();
|
||||||
|
_horizontalBodyScrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: widget.cellDecoration,
|
decoration: widget.cellDecoration,
|
||||||
child: Scrollbar(
|
child: Column(
|
||||||
controller: _verticalScrollController,
|
children: [
|
||||||
thumbVisibility: true,
|
Container(
|
||||||
trackVisibility: true,
|
decoration: widget.headerDecoration ??
|
||||||
child: Scrollbar(
|
const BoxDecoration(color: ColorsManager.boxColor),
|
||||||
controller: _horizontalScrollController,
|
|
||||||
thumbVisibility: true,
|
|
||||||
trackVisibility: true,
|
|
||||||
notificationPredicate: (notif) => notif.depth == 1,
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
controller: _verticalScrollController,
|
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
controller: _horizontalScrollController,
|
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
controller: _horizontalHeaderScrollController,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: widget.size.width,
|
width: widget.size.width,
|
||||||
child: Column(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
||||||
decoration: widget.headerDecoration ??
|
...List.generate(widget.headers.length, (index) {
|
||||||
const BoxDecoration(
|
return _buildTableHeaderCell(
|
||||||
color: ColorsManager.boxColor,
|
widget.headers[index], index);
|
||||||
),
|
}),
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
|
||||||
...List.generate(widget.headers.length, (index) {
|
|
||||||
return _buildTableHeaderCell(
|
|
||||||
widget.headers[index], index);
|
|
||||||
})
|
|
||||||
//...widget.headers.map((header) => _buildTableHeaderCell(header)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
widget.isEmpty
|
|
||||||
? SizedBox(
|
|
||||||
height: widget.size.height * 0.5,
|
|
||||||
width: widget.size.width,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(Assets.emptyTable),
|
|
||||||
const SizedBox(
|
|
||||||
height: 15,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
widget.tableName == 'AccessManagement'
|
|
||||||
? 'No Password '
|
|
||||||
: 'No Devices',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodySmall!
|
|
||||||
.copyWith(
|
|
||||||
color:
|
|
||||||
ColorsManager.grayColor),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Column(
|
|
||||||
children:
|
|
||||||
List.generate(widget.data.length, (index) {
|
|
||||||
final row = widget.data[index];
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
if (widget.withCheckBox)
|
|
||||||
_buildRowCheckbox(
|
|
||||||
index, widget.size.height * 0.08),
|
|
||||||
...row.map((cell) => _buildTableCell(
|
|
||||||
cell.toString(),
|
|
||||||
widget.size.height * 0.08)),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Expanded(
|
||||||
|
child: Scrollbar(
|
||||||
|
controller: _verticalScrollController,
|
||||||
|
thumbVisibility: true,
|
||||||
|
trackVisibility: true,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: _verticalScrollController,
|
||||||
|
child: Scrollbar(
|
||||||
|
controller: _horizontalBodyScrollController,
|
||||||
|
thumbVisibility: false,
|
||||||
|
trackVisibility: false,
|
||||||
|
notificationPredicate: (notif) => notif.depth == 1,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
controller: _horizontalBodyScrollController,
|
||||||
|
child: SizedBox(
|
||||||
|
width: widget.size.width,
|
||||||
|
child: widget.isEmpty
|
||||||
|
? _buildEmptyState()
|
||||||
|
: Column(
|
||||||
|
children:
|
||||||
|
List.generate(widget.data.length, (rowIndex) {
|
||||||
|
final row = widget.data[rowIndex];
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
if (widget.withCheckBox)
|
||||||
|
_buildRowCheckbox(
|
||||||
|
rowIndex, widget.size.height * 0.08),
|
||||||
|
...row.asMap().entries.map((entry) {
|
||||||
|
return _buildTableCell(
|
||||||
|
entry.value.toString(),
|
||||||
|
widget.size.height * 0.08,
|
||||||
|
rowIndex: rowIndex,
|
||||||
|
columnIndex: entry.key,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -218,6 +215,32 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildEmptyState() => Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(Assets.emptyTable),
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
Text(
|
||||||
|
widget.tableName == 'AccessManagement'
|
||||||
|
? 'No Password '
|
||||||
|
: 'No Devices',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall!
|
||||||
|
.copyWith(color: ColorsManager.grayColor),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
Widget _buildRowCheckbox(int index, double size) {
|
Widget _buildRowCheckbox(int index, double size) {
|
||||||
return Container(
|
return Container(
|
||||||
width: 50,
|
width: 50,
|
||||||
@ -272,13 +295,23 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTableCell(String content, double size) {
|
Widget _buildTableCell(
|
||||||
|
String content,
|
||||||
|
double size, {
|
||||||
|
required int rowIndex,
|
||||||
|
required int columnIndex,
|
||||||
|
}) {
|
||||||
bool isBatteryLevel = content.endsWith('%');
|
bool isBatteryLevel = content.endsWith('%');
|
||||||
double? batteryLevel;
|
double? batteryLevel;
|
||||||
|
|
||||||
if (isBatteryLevel) {
|
if (isBatteryLevel) {
|
||||||
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
|
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
|
||||||
}
|
}
|
||||||
|
bool isSettingsColumn = widget.headers[columnIndex] == 'Settings';
|
||||||
|
|
||||||
|
if (isSettingsColumn) {
|
||||||
|
return _buildSettingsIcon(rowIndex, size);
|
||||||
|
}
|
||||||
|
|
||||||
Color? statusColor;
|
Color? statusColor;
|
||||||
switch (content) {
|
switch (content) {
|
||||||
@ -330,4 +363,23 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildSettingsIcon(int rowIndex, double size) {
|
||||||
|
return Container(
|
||||||
|
height: size,
|
||||||
|
width: 120,
|
||||||
|
padding: const EdgeInsets.all(5.0),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(color: ColorsManager.boxDivider, width: 1.0),
|
||||||
|
),
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: IconButton(
|
||||||
|
icon: SvgPicture.asset(Assets.settings),
|
||||||
|
onPressed: () => widget.onSettingsPressed?.call(rowIndex),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ class _TableRow extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (!isLast)
|
if (!isLast)
|
||||||
Divider(
|
const Divider(
|
||||||
height: 1,
|
height: 1,
|
||||||
thickness: 1,
|
thickness: 1,
|
||||||
color: ColorsManager.boxDivider,
|
color: ColorsManager.boxDivider,
|
||||||
@ -110,12 +110,14 @@ class DynamicTableScreen extends StatefulWidget {
|
|||||||
final List<String> titles;
|
final List<String> titles;
|
||||||
final List<List<Widget>> rows;
|
final List<List<Widget>> rows;
|
||||||
final void Function(int columnIndex)? onFilter;
|
final void Function(int columnIndex)? onFilter;
|
||||||
|
final double tableSize;
|
||||||
|
|
||||||
const DynamicTableScreen({
|
const DynamicTableScreen({
|
||||||
required this.titles,
|
required this.titles,
|
||||||
required this.rows,
|
required this.rows,
|
||||||
required this.onFilter,
|
required this.onFilter,
|
||||||
Key? key,
|
Key? key,
|
||||||
|
required this.tableSize,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -205,7 +207,8 @@ class _DynamicTableScreenState extends State<DynamicTableScreen> {
|
|||||||
bottomRight: Radius.circular(15),
|
bottomRight: Radius.circular(15),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: ListView(
|
||||||
|
shrinkWrap: true,
|
||||||
children: [
|
children: [
|
||||||
for (int rowIndex = 0; rowIndex < widget.rows.length; rowIndex++)
|
for (int rowIndex = 0; rowIndex < widget.rows.length; rowIndex++)
|
||||||
_TableRow(
|
_TableRow(
|
||||||
@ -253,7 +256,7 @@ class _DynamicTableScreenState extends State<DynamicTableScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildHeader(),
|
_buildHeader(),
|
||||||
_buildBody(),
|
Container(height: widget.tableSize - 37, child: _buildBody()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -27,7 +27,8 @@ class UsersPage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final TextEditingController searchController = TextEditingController();
|
final TextEditingController searchController = TextEditingController();
|
||||||
|
|
||||||
Widget actionButton({bool isActive = false, required String title, Function()? onTap}) {
|
Widget actionButton(
|
||||||
|
{bool isActive = false, required String title, Function()? onTap}) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -60,7 +61,8 @@ class UsersPage extends StatelessWidget {
|
|||||||
: ColorsManager.disabledPink.withOpacity(0.5),
|
: ColorsManager.disabledPink.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 5, top: 5),
|
padding:
|
||||||
|
const EdgeInsets.only(left: 10, right: 10, bottom: 5, top: 5),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@ -84,12 +86,15 @@ class UsersPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget changeIconStatus(
|
Widget changeIconStatus(
|
||||||
{required String userId, required String status, required Function()? onTap}) {
|
{required String userId,
|
||||||
|
required String status,
|
||||||
|
required Function()? onTap}) {
|
||||||
return Center(
|
return Center(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5),
|
padding:
|
||||||
|
const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5),
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
status == "invited"
|
status == "invited"
|
||||||
? Assets.invitedIcon
|
? Assets.invitedIcon
|
||||||
@ -114,8 +119,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: ListView(
|
child: Column(
|
||||||
shrinkWrap: true,
|
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@ -188,292 +192,325 @@ class UsersPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 25),
|
const SizedBox(height: 20),
|
||||||
DynamicTableScreen(
|
Container(
|
||||||
onFilter: (columnIndex) {
|
height: screenSize.height * 0.65,
|
||||||
if (columnIndex == 0) {
|
child: DynamicTableScreen(
|
||||||
showNameMenu(
|
tableSize: screenSize.height * 0.65,
|
||||||
context: context,
|
onFilter: (columnIndex) {
|
||||||
isSelected: _blocRole.currentSortOrder,
|
if (columnIndex == 0) {
|
||||||
aToZTap: () {
|
showNameMenu(
|
||||||
context.read<UserTableBloc>().add(const SortUsersByNameAsc());
|
context: context,
|
||||||
},
|
isSelected: _blocRole.currentSortOrder,
|
||||||
zToaTap: () {
|
aToZTap: () {
|
||||||
context.read<UserTableBloc>().add(const SortUsersByNameDesc());
|
context
|
||||||
},
|
.read<UserTableBloc>()
|
||||||
);
|
.add(const SortUsersByNameAsc());
|
||||||
}
|
},
|
||||||
if (columnIndex == 2) {
|
zToaTap: () {
|
||||||
final Map<String, bool> checkboxStates = {
|
context
|
||||||
for (var item in _blocRole.jobTitle)
|
.read<UserTableBloc>()
|
||||||
item: _blocRole.selectedJobTitles.contains(item),
|
.add(const SortUsersByNameDesc());
|
||||||
};
|
},
|
||||||
final RenderBox overlay =
|
);
|
||||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
}
|
||||||
|
if (columnIndex == 2) {
|
||||||
|
final Map<String, bool> checkboxStates = {
|
||||||
|
for (var item in _blocRole.jobTitle)
|
||||||
|
item: _blocRole.selectedJobTitles.contains(item),
|
||||||
|
};
|
||||||
|
final RenderBox overlay = Overlay.of(context)
|
||||||
|
.context
|
||||||
|
.findRenderObject() as RenderBox;
|
||||||
|
|
||||||
showPopUpFilterMenu(
|
showPopUpFilterMenu(
|
||||||
position: RelativeRect.fromLTRB(
|
position: RelativeRect.fromLTRB(
|
||||||
overlay.size.width / 5.3,
|
overlay.size.width / 5.3,
|
||||||
240,
|
240,
|
||||||
overlay.size.width / 4,
|
overlay.size.width / 4,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
list: _blocRole.jobTitle,
|
list: _blocRole.jobTitle,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortJopTitle,
|
isSelected: _blocRole.currentSortJopTitle,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
searchController.clear();
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
.map((entry) => entry.key)
|
.map((entry) => entry.key)
|
||||||
.toList();
|
.toList();
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
_blocRole.add(FilterUsersByJobEvent(
|
_blocRole.add(FilterUsersByJobEvent(
|
||||||
selectedJob: selectedItems,
|
selectedJob: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortJopTitle,
|
sortOrder: _blocRole.currentSortJopTitle,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortJopTitle = v;
|
_blocRole.currentSortJopTitle = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortJopTitle = v;
|
_blocRole.currentSortJopTitle = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (columnIndex == 3) {
|
if (columnIndex == 3) {
|
||||||
final Map<String, bool> checkboxStates = {
|
final Map<String, bool> checkboxStates = {
|
||||||
for (var item in _blocRole.roleTypes)
|
for (var item in _blocRole.roleTypes)
|
||||||
item: _blocRole.selectedRoles.contains(item),
|
item: _blocRole.selectedRoles.contains(item),
|
||||||
};
|
};
|
||||||
final RenderBox overlay =
|
final RenderBox overlay = Overlay.of(context)
|
||||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
.context
|
||||||
showPopUpFilterMenu(
|
.findRenderObject() as RenderBox;
|
||||||
position: RelativeRect.fromLTRB(
|
showPopUpFilterMenu(
|
||||||
overlay.size.width / 4,
|
position: RelativeRect.fromLTRB(
|
||||||
240,
|
overlay.size.width / 4,
|
||||||
overlay.size.width / 4,
|
240,
|
||||||
0,
|
overlay.size.width / 4,
|
||||||
),
|
0,
|
||||||
list: _blocRole.roleTypes,
|
),
|
||||||
context: context,
|
list: _blocRole.roleTypes,
|
||||||
checkboxStates: checkboxStates,
|
context: context,
|
||||||
isSelected: _blocRole.currentSortRole,
|
checkboxStates: checkboxStates,
|
||||||
onOkPressed: () {
|
isSelected: _blocRole.currentSortRole,
|
||||||
searchController.clear();
|
onOkPressed: () {
|
||||||
_blocRole.add(FilterClearEvent());
|
searchController.clear();
|
||||||
final selectedItems = checkboxStates.entries
|
_blocRole.add(FilterClearEvent());
|
||||||
.where((entry) => entry.value)
|
final selectedItems = checkboxStates.entries
|
||||||
.map((entry) => entry.key)
|
.where((entry) => entry.value)
|
||||||
.toList();
|
.map((entry) => entry.key)
|
||||||
Navigator.of(context).pop();
|
.toList();
|
||||||
context.read<UserTableBloc>().add(FilterUsersByRoleEvent(
|
Navigator.of(context).pop();
|
||||||
selectedRoles: selectedItems,
|
context.read<UserTableBloc>().add(
|
||||||
sortOrder: _blocRole.currentSortRole));
|
FilterUsersByRoleEvent(
|
||||||
},
|
selectedRoles: selectedItems,
|
||||||
onSortAtoZ: (v) {
|
sortOrder: _blocRole.currentSortRole));
|
||||||
_blocRole.currentSortRole = v;
|
},
|
||||||
},
|
onSortAtoZ: (v) {
|
||||||
onSortZtoA: (v) {
|
_blocRole.currentSortRole = v;
|
||||||
_blocRole.currentSortRole = v;
|
},
|
||||||
},
|
onSortZtoA: (v) {
|
||||||
);
|
_blocRole.currentSortRole = v;
|
||||||
}
|
},
|
||||||
if (columnIndex == 4) {
|
);
|
||||||
showDateFilterMenu(
|
}
|
||||||
context: context,
|
if (columnIndex == 4) {
|
||||||
isSelected: _blocRole.currentSortOrder,
|
showDateFilterMenu(
|
||||||
aToZTap: () {
|
context: context,
|
||||||
context.read<UserTableBloc>().add(const DateNewestToOldestEvent());
|
isSelected: _blocRole.currentSortOrder,
|
||||||
},
|
aToZTap: () {
|
||||||
zToaTap: () {
|
context
|
||||||
context.read<UserTableBloc>().add(const DateOldestToNewestEvent());
|
.read<UserTableBloc>()
|
||||||
},
|
.add(const DateNewestToOldestEvent());
|
||||||
);
|
},
|
||||||
}
|
zToaTap: () {
|
||||||
if (columnIndex == 6) {
|
context
|
||||||
final Map<String, bool> checkboxStates = {
|
.read<UserTableBloc>()
|
||||||
for (var item in _blocRole.createdBy)
|
.add(const DateOldestToNewestEvent());
|
||||||
item: _blocRole.selectedCreatedBy.contains(item),
|
},
|
||||||
};
|
);
|
||||||
final RenderBox overlay =
|
}
|
||||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
if (columnIndex == 6) {
|
||||||
showPopUpFilterMenu(
|
final Map<String, bool> checkboxStates = {
|
||||||
position: RelativeRect.fromLTRB(
|
for (var item in _blocRole.createdBy)
|
||||||
overlay.size.width / 1,
|
item: _blocRole.selectedCreatedBy.contains(item),
|
||||||
240,
|
};
|
||||||
overlay.size.width / 4,
|
final RenderBox overlay = Overlay.of(context)
|
||||||
0,
|
.context
|
||||||
),
|
.findRenderObject() as RenderBox;
|
||||||
list: _blocRole.createdBy,
|
showPopUpFilterMenu(
|
||||||
context: context,
|
position: RelativeRect.fromLTRB(
|
||||||
checkboxStates: checkboxStates,
|
overlay.size.width / 1,
|
||||||
isSelected: _blocRole.currentSortCreatedBy,
|
240,
|
||||||
onOkPressed: () {
|
overlay.size.width / 4,
|
||||||
searchController.clear();
|
0,
|
||||||
_blocRole.add(FilterClearEvent());
|
),
|
||||||
final selectedItems = checkboxStates.entries
|
list: _blocRole.createdBy,
|
||||||
.where((entry) => entry.value)
|
context: context,
|
||||||
.map((entry) => entry.key)
|
checkboxStates: checkboxStates,
|
||||||
.toList();
|
isSelected: _blocRole.currentSortCreatedBy,
|
||||||
Navigator.of(context).pop();
|
onOkPressed: () {
|
||||||
_blocRole.add(FilterUsersByCreatedEvent(
|
searchController.clear();
|
||||||
selectedCreatedBy: selectedItems,
|
_blocRole.add(FilterClearEvent());
|
||||||
sortOrder: _blocRole.currentSortCreatedBy));
|
final selectedItems = checkboxStates.entries
|
||||||
},
|
.where((entry) => entry.value)
|
||||||
onSortAtoZ: (v) {
|
.map((entry) => entry.key)
|
||||||
_blocRole.currentSortCreatedBy = v;
|
.toList();
|
||||||
},
|
Navigator.of(context).pop();
|
||||||
onSortZtoA: (v) {
|
_blocRole.add(FilterUsersByCreatedEvent(
|
||||||
_blocRole.currentSortCreatedBy = v;
|
selectedCreatedBy: selectedItems,
|
||||||
},
|
sortOrder: _blocRole.currentSortCreatedBy));
|
||||||
);
|
},
|
||||||
}
|
onSortAtoZ: (v) {
|
||||||
if (columnIndex == 7) {
|
_blocRole.currentSortCreatedBy = v;
|
||||||
final Map<String, bool> checkboxStates = {
|
},
|
||||||
for (var item in _blocRole.status)
|
onSortZtoA: (v) {
|
||||||
item: _blocRole.selectedStatuses.contains(item),
|
_blocRole.currentSortCreatedBy = v;
|
||||||
};
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (columnIndex == 7) {
|
||||||
|
final Map<String, bool> checkboxStates = {
|
||||||
|
for (var item in _blocRole.status)
|
||||||
|
item: _blocRole.selectedStatuses.contains(item),
|
||||||
|
};
|
||||||
|
|
||||||
final RenderBox overlay =
|
final RenderBox overlay = Overlay.of(context)
|
||||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
.context
|
||||||
showPopUpFilterMenu(
|
.findRenderObject() as RenderBox;
|
||||||
position: RelativeRect.fromLTRB(
|
showPopUpFilterMenu(
|
||||||
overlay.size.width / 0,
|
position: RelativeRect.fromLTRB(
|
||||||
240,
|
overlay.size.width / 0,
|
||||||
overlay.size.width / 5,
|
240,
|
||||||
0,
|
overlay.size.width / 5,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
list: _blocRole.status,
|
||||||
|
context: context,
|
||||||
|
checkboxStates: checkboxStates,
|
||||||
|
isSelected: _blocRole.currentSortStatus,
|
||||||
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
|
_blocRole.add(FilterClearEvent());
|
||||||
|
final selectedItems = checkboxStates.entries
|
||||||
|
.where((entry) => entry.value)
|
||||||
|
.map((entry) => entry.key)
|
||||||
|
.toList();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
_blocRole.add(FilterUsersByDeActevateEvent(
|
||||||
|
selectedActivate: selectedItems,
|
||||||
|
sortOrder: _blocRole.currentSortStatus));
|
||||||
|
},
|
||||||
|
onSortAtoZ: (v) {
|
||||||
|
_blocRole.currentSortStatus = v;
|
||||||
|
},
|
||||||
|
onSortZtoA: (v) {
|
||||||
|
_blocRole.currentSortStatus = v;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (columnIndex == 8) {
|
||||||
|
showDeActivateFilterMenu(
|
||||||
|
context: context,
|
||||||
|
isSelected: _blocRole.currentSortOrderDate,
|
||||||
|
aToZTap: () {
|
||||||
|
context
|
||||||
|
.read<UserTableBloc>()
|
||||||
|
.add(const DateNewestToOldestEvent());
|
||||||
|
},
|
||||||
|
zToaTap: () {
|
||||||
|
context
|
||||||
|
.read<UserTableBloc>()
|
||||||
|
.add(const DateOldestToNewestEvent());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
titles: const [
|
||||||
|
"Full Name",
|
||||||
|
"Email Address",
|
||||||
|
"Job Title",
|
||||||
|
"Role",
|
||||||
|
"Creation Date",
|
||||||
|
"Creation Time",
|
||||||
|
"Created By",
|
||||||
|
"Status",
|
||||||
|
"De/Activate",
|
||||||
|
"Action"
|
||||||
|
],
|
||||||
|
rows: state.users.map((user) {
|
||||||
|
return [
|
||||||
|
Text('${user.firstName} ${user.lastName}'),
|
||||||
|
Text(user.email),
|
||||||
|
Text(user.jobTitle),
|
||||||
|
Text(user.roleType ?? ''),
|
||||||
|
Text(user.createdDate ?? ''),
|
||||||
|
Text(user.createdTime ?? ''),
|
||||||
|
Text(user.invitedBy),
|
||||||
|
status(
|
||||||
|
status: user.isEnabled == false
|
||||||
|
? 'disabled'
|
||||||
|
: user.status,
|
||||||
),
|
),
|
||||||
list: _blocRole.status,
|
changeIconStatus(
|
||||||
context: context,
|
status: user.isEnabled == false
|
||||||
checkboxStates: checkboxStates,
|
? 'disabled'
|
||||||
isSelected: _blocRole.currentSortStatus,
|
: user.status,
|
||||||
onOkPressed: () {
|
userId: user.uuid,
|
||||||
searchController.clear();
|
onTap: user.status != "invited"
|
||||||
_blocRole.add(FilterClearEvent());
|
? () {
|
||||||
final selectedItems = checkboxStates.entries
|
context.read<UserTableBloc>().add(
|
||||||
.where((entry) => entry.value)
|
ChangeUserStatus(
|
||||||
.map((entry) => entry.key)
|
userId: user.uuid,
|
||||||
.toList();
|
newStatus: user.isEnabled == false
|
||||||
Navigator.of(context).pop();
|
? 'disabled'
|
||||||
_blocRole.add(FilterUsersByDeActevateEvent(
|
: user.status));
|
||||||
selectedActivate: selectedItems,
|
}
|
||||||
sortOrder: _blocRole.currentSortStatus));
|
: null,
|
||||||
},
|
),
|
||||||
onSortAtoZ: (v) {
|
Row(
|
||||||
_blocRole.currentSortStatus = v;
|
children: [
|
||||||
},
|
user.isEnabled != false
|
||||||
onSortZtoA: (v) {
|
? actionButton(
|
||||||
_blocRole.currentSortStatus = v;
|
isActive: true,
|
||||||
},
|
title: "Edit",
|
||||||
);
|
onTap: () {
|
||||||
}
|
context
|
||||||
if (columnIndex == 8) {
|
.read<SpaceTreeBloc>()
|
||||||
showDeActivateFilterMenu(
|
.add(ClearCachedData());
|
||||||
context: context,
|
showDialog(
|
||||||
isSelected: _blocRole.currentSortOrderDate,
|
context: context,
|
||||||
aToZTap: () {
|
barrierDismissible: false,
|
||||||
context.read<UserTableBloc>().add(const DateNewestToOldestEvent());
|
builder: (BuildContext context) {
|
||||||
},
|
return EditUserDialog(
|
||||||
zToaTap: () {
|
userId: user.uuid);
|
||||||
context.read<UserTableBloc>().add(const DateOldestToNewestEvent());
|
},
|
||||||
},
|
).then((v) {
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
titles: const [
|
|
||||||
"Full Name",
|
|
||||||
"Email Address",
|
|
||||||
"Job Title",
|
|
||||||
"Role",
|
|
||||||
"Creation Date",
|
|
||||||
"Creation Time",
|
|
||||||
"Created By",
|
|
||||||
"Status",
|
|
||||||
"De/Activate",
|
|
||||||
"Action"
|
|
||||||
],
|
|
||||||
rows: state.users.map((user) {
|
|
||||||
return [
|
|
||||||
Text('${user.firstName} ${user.lastName}'),
|
|
||||||
Text(user.email),
|
|
||||||
Text(user.jobTitle),
|
|
||||||
Text(user.roleType ?? ''),
|
|
||||||
Text(user.createdDate ?? ''),
|
|
||||||
Text(user.createdTime ?? ''),
|
|
||||||
Text(user.invitedBy),
|
|
||||||
status(
|
|
||||||
status: user.isEnabled == false ? 'disabled' : user.status,
|
|
||||||
),
|
|
||||||
changeIconStatus(
|
|
||||||
status: user.isEnabled == false ? 'disabled' : user.status,
|
|
||||||
userId: user.uuid,
|
|
||||||
onTap: user.status != "invited"
|
|
||||||
? () {
|
|
||||||
context.read<UserTableBloc>().add(ChangeUserStatus(
|
|
||||||
userId: user.uuid,
|
|
||||||
newStatus:
|
|
||||||
user.isEnabled == false ? 'disabled' : user.status));
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
user.isEnabled != false
|
|
||||||
? actionButton(
|
|
||||||
isActive: true,
|
|
||||||
title: "Edit",
|
|
||||||
onTap: () {
|
|
||||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return EditUserDialog(userId: user.uuid);
|
|
||||||
},
|
|
||||||
).then((v) {
|
|
||||||
if (v != null) {
|
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
_blocRole.add(const GetUsers());
|
if (v != null) {
|
||||||
|
_blocRole.add(const GetUsers());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: actionButton(
|
||||||
|
title: "Edit",
|
||||||
|
),
|
||||||
|
actionButton(
|
||||||
|
title: "Delete",
|
||||||
|
onTap: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DeleteUserDialog(
|
||||||
|
onTapDelete: () async {
|
||||||
|
try {
|
||||||
|
_blocRole.add(DeleteUserEvent(
|
||||||
|
user.uuid, context));
|
||||||
|
await Future.delayed(
|
||||||
|
const Duration(seconds: 2));
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
).then((v) {
|
||||||
: actionButton(
|
if (v != null) {
|
||||||
title: "Edit",
|
_blocRole.add(const GetUsers());
|
||||||
),
|
}
|
||||||
actionButton(
|
});
|
||||||
title: "Delete",
|
},
|
||||||
onTap: () {
|
),
|
||||||
showDialog(
|
],
|
||||||
context: context,
|
),
|
||||||
barrierDismissible: false,
|
];
|
||||||
builder: (BuildContext context) {
|
}).toList(),
|
||||||
return DeleteUserDialog(onTapDelete: () async {
|
),
|
||||||
try {
|
|
||||||
_blocRole.add(DeleteUserEvent(user.uuid, context));
|
|
||||||
await Future.delayed(const Duration(seconds: 2));
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
).then((v) {
|
|
||||||
if (v != null) {
|
|
||||||
_blocRole.add(const GetUsers());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}).toList(),
|
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
@ -486,14 +523,20 @@ class UsersPage extends StatelessWidget {
|
|||||||
visiblePagesCount: 4,
|
visiblePagesCount: 4,
|
||||||
buttonRadius: 10,
|
buttonRadius: 10,
|
||||||
selectedButtonColor: ColorsManager.secondaryColor,
|
selectedButtonColor: ColorsManager.secondaryColor,
|
||||||
buttonUnSelectedBorderColor: ColorsManager.grayBorder,
|
buttonUnSelectedBorderColor:
|
||||||
lastPageIcon: const Icon(Icons.keyboard_double_arrow_right),
|
ColorsManager.grayBorder,
|
||||||
firstPageIcon: const Icon(Icons.keyboard_double_arrow_left),
|
lastPageIcon:
|
||||||
totalPages:
|
const Icon(Icons.keyboard_double_arrow_right),
|
||||||
(_blocRole.totalUsersCount.length / _blocRole.itemsPerPage).ceil(),
|
firstPageIcon:
|
||||||
|
const Icon(Icons.keyboard_double_arrow_left),
|
||||||
|
totalPages: (_blocRole.totalUsersCount.length /
|
||||||
|
_blocRole.itemsPerPage)
|
||||||
|
.ceil(),
|
||||||
currentPage: _blocRole.currentPage,
|
currentPage: _blocRole.currentPage,
|
||||||
onPageChanged: (int pageNumber) {
|
onPageChanged: (int pageNumber) {
|
||||||
context.read<UserTableBloc>().add(ChangePage(pageNumber));
|
context
|
||||||
|
.read<UserTableBloc>()
|
||||||
|
.add(ChangePage(pageNumber));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Reference in New Issue
Block a user