mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
fix selection from dynamic table
This commit is contained in:
@ -82,6 +82,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: DynamicTable(
|
child: DynamicTable(
|
||||||
|
uuidIndex: 0,
|
||||||
isEmpty: filteredData.isEmpty,
|
isEmpty: filteredData.isEmpty,
|
||||||
withCheckBox: false,
|
withCheckBox: false,
|
||||||
size: MediaQuery.of(context).size,
|
size: MediaQuery.of(context).size,
|
||||||
|
@ -14,6 +14,7 @@ class DynamicTable extends StatefulWidget {
|
|||||||
final void Function(bool?)? selectAll;
|
final void Function(bool?)? selectAll;
|
||||||
final void Function(int, bool, dynamic)? onRowSelected;
|
final void Function(int, bool, dynamic)? onRowSelected;
|
||||||
final List<String>? initialSelectedIds;
|
final List<String>? initialSelectedIds;
|
||||||
|
final int uuidIndex;
|
||||||
const DynamicTable({
|
const DynamicTable({
|
||||||
super.key,
|
super.key,
|
||||||
required this.headers,
|
required this.headers,
|
||||||
@ -26,6 +27,7 @@ class DynamicTable extends StatefulWidget {
|
|||||||
this.selectAll,
|
this.selectAll,
|
||||||
this.onRowSelected,
|
this.onRowSelected,
|
||||||
this.initialSelectedIds,
|
this.initialSelectedIds,
|
||||||
|
required this.uuidIndex,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -38,9 +40,24 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_initializeSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(DynamicTable oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (oldWidget.data != widget.data) {
|
||||||
|
_initializeSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initializeSelection() {
|
||||||
_selected = List<bool>.generate(widget.data.length, (index) {
|
_selected = List<bool>.generate(widget.data.length, (index) {
|
||||||
|
// Check if the initialSelectedIds contains the deviceUuid
|
||||||
|
// uuidIndex is the index of the column containing the deviceUuid
|
||||||
|
final deviceUuid = widget.data[index][widget.uuidIndex];
|
||||||
return widget.initialSelectedIds != null &&
|
return widget.initialSelectedIds != null &&
|
||||||
widget.initialSelectedIds!.contains(widget.data[index][1]);
|
widget.initialSelectedIds!.contains(deviceUuid);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +88,7 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
children: [
|
children: [
|
||||||
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
||||||
...widget.headers
|
...widget.headers
|
||||||
.map((header) => _buildTableHeaderCell(header))
|
.map((header) => _buildTableHeaderCell(header)),
|
||||||
.toList(),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -119,11 +135,9 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
if (widget.withCheckBox)
|
if (widget.withCheckBox)
|
||||||
_buildRowCheckbox(
|
_buildRowCheckbox(
|
||||||
index, widget.size.height * 0.10),
|
index, widget.size.height * 0.10),
|
||||||
...row
|
...row.map((cell) => _buildTableCell(
|
||||||
.map((cell) => _buildTableCell(
|
|
||||||
cell.toString(),
|
cell.toString(),
|
||||||
widget.size.height * 0.10))
|
widget.size.height * 0.10)),
|
||||||
.toList(),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -28,11 +28,12 @@ class DeviceManagementBloc
|
|||||||
emit(DeviceManagementLoading());
|
emit(DeviceManagementLoading());
|
||||||
try {
|
try {
|
||||||
final devices = await DevicesManagementApi().fetchDevices();
|
final devices = await DevicesManagementApi().fetchDevices();
|
||||||
|
_selectedDevices.clear();
|
||||||
_devices = devices;
|
_devices = devices;
|
||||||
_calculateDeviceCounts();
|
_calculateDeviceCounts();
|
||||||
emit(DeviceManagementLoaded(
|
emit(DeviceManagementLoaded(
|
||||||
devices: devices,
|
devices: devices,
|
||||||
selectedIndex: _selectedIndex,
|
selectedIndex: 0,
|
||||||
onlineCount: _onlineCount,
|
onlineCount: _onlineCount,
|
||||||
offlineCount: _offlineCount,
|
offlineCount: _offlineCount,
|
||||||
lowBatteryCount: _lowBatteryCount,
|
lowBatteryCount: _lowBatteryCount,
|
||||||
@ -64,6 +65,8 @@ class DeviceManagementBloc
|
|||||||
onlineCount: _onlineCount,
|
onlineCount: _onlineCount,
|
||||||
offlineCount: _offlineCount,
|
offlineCount: _offlineCount,
|
||||||
lowBatteryCount: _lowBatteryCount,
|
lowBatteryCount: _lowBatteryCount,
|
||||||
|
selectedDevice:
|
||||||
|
_selectedDevices.isNotEmpty ? _selectedDevices.first : null,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,8 +79,10 @@ class DeviceManagementBloc
|
|||||||
|
|
||||||
void _onSelectDevice(
|
void _onSelectDevice(
|
||||||
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||||
if (_selectedDevices.contains(event.selectedDevice)) {
|
final selectedUuid = event.selectedDevice.uuid;
|
||||||
_selectedDevices.remove(event.selectedDevice);
|
|
||||||
|
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
||||||
|
_selectedDevices.removeWhere((device) => device.uuid == selectedUuid);
|
||||||
} else {
|
} else {
|
||||||
_selectedDevices.add(event.selectedDevice);
|
_selectedDevices.add(event.selectedDevice);
|
||||||
}
|
}
|
||||||
@ -130,6 +135,9 @@ class DeviceManagementBloc
|
|||||||
void _onSearchDevices(
|
void _onSearchDevices(
|
||||||
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||||
if (_devices.isNotEmpty) {
|
if (_devices.isNotEmpty) {
|
||||||
|
_selectedDevices.clear();
|
||||||
|
_selectedIndex = 0;
|
||||||
|
|
||||||
final filteredDevices = _devices.where((device) {
|
final filteredDevices = _devices.where((device) {
|
||||||
final matchesCommunity = event.community == null ||
|
final matchesCommunity = event.community == null ||
|
||||||
event.community!.isEmpty ||
|
event.community!.isEmpty ||
|
||||||
@ -151,7 +159,6 @@ class DeviceManagementBloc
|
|||||||
false);
|
false);
|
||||||
return matchesCommunity && matchesUnit && matchesProductName;
|
return matchesCommunity && matchesUnit && matchesProductName;
|
||||||
}).toList();
|
}).toList();
|
||||||
_selectedDevices = [];
|
|
||||||
emit(DeviceManagementFiltered(
|
emit(DeviceManagementFiltered(
|
||||||
filteredDevices: filteredDevices,
|
filteredDevices: filteredDevices,
|
||||||
selectedIndex: 0,
|
selectedIndex: 0,
|
||||||
|
@ -42,6 +42,10 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
offlineCount = state.offlineCount;
|
offlineCount = state.offlineCount;
|
||||||
lowBatteryCount = state.lowBatteryCount;
|
lowBatteryCount = state.lowBatteryCount;
|
||||||
isControlButtonEnabled = state.selectedDevice != null;
|
isControlButtonEnabled = state.selectedDevice != null;
|
||||||
|
} else if (state is DeviceManagementInitial) {
|
||||||
|
devicesToShow = [];
|
||||||
|
selectedIndex = 0;
|
||||||
|
isControlButtonEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final tabs = [
|
final tabs = [
|
||||||
@ -125,6 +129,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
},
|
},
|
||||||
withCheckBox: true,
|
withCheckBox: true,
|
||||||
size: context.screenSize,
|
size: context.screenSize,
|
||||||
|
uuidIndex: 2,
|
||||||
headers: const [
|
headers: const [
|
||||||
'Device Name',
|
'Device Name',
|
||||||
'Product Name',
|
'Product Name',
|
||||||
@ -153,10 +158,15 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
(device.updateTime ?? 0) * 1000)),
|
(device.updateTime ?? 0) * 1000)),
|
||||||
];
|
];
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
initialSelectedIds: context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.selectedDevices
|
||||||
|
.map((device) => device.uuid!)
|
||||||
|
.toList(),
|
||||||
isEmpty: devicesToShow.isEmpty,
|
isEmpty: devicesToShow.isEmpty,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -16,11 +16,11 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
||||||
List<Node> sourcesList = [];
|
List<Node> sourcesList = [];
|
||||||
List<Node> destinationsList = [];
|
List<Node> destinationsList = [];
|
||||||
static UserModel? user;
|
UserModel? user;
|
||||||
|
|
||||||
HomeBloc() : super((HomeInitial())) {
|
HomeBloc() : super((HomeInitial())) {
|
||||||
on<CreateNewNode>(_createNode);
|
on<CreateNewNode>(_createNode);
|
||||||
fetchUserInfo();
|
on<FetchUserInfo>(_fetchUserInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
||||||
@ -39,10 +39,12 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
emit(HomeUpdateTree(graph: graph, builder: builder));
|
emit(HomeUpdateTree(graph: graph, builder: builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future fetchUserInfo() async {
|
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
||||||
try {
|
try {
|
||||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
var uuid =
|
||||||
|
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
user = await HomeApi().fetchUserInfo(uuid);
|
user = await HomeApi().fetchUserInfo(uuid);
|
||||||
|
emit(HomeInitial());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -17,3 +17,7 @@ class CreateNewNode extends HomeEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [sourceNode, destinationNode];
|
List<Object> get props => [sourceNode, destinationNode];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FetchUserInfo extends HomeEvent {
|
||||||
|
const FetchUserInfo();
|
||||||
|
}
|
@ -1,11 +1,25 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
import 'package:syncrow_web/pages/home/view/home_page_mobile.dart';
|
import 'package:syncrow_web/pages/home/view/home_page_mobile.dart';
|
||||||
import 'package:syncrow_web/pages/home/view/home_page_web.dart';
|
import 'package:syncrow_web/pages/home/view/home_page_web.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class HomePage extends StatelessWidget with HelperResponsiveLayout {
|
class HomePage extends StatefulWidget {
|
||||||
const HomePage({super.key});
|
const HomePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomePage> createState() => _HomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomePageState extends State<HomePage> with HelperResponsiveLayout {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
context.read<HomeBloc>().add(const FetchUserInfo());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isSmallScreen = isSmallScreenSize(context);
|
final isSmallScreen = isSmallScreenSize(context);
|
||||||
|
@ -10,6 +10,7 @@ import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
|||||||
|
|
||||||
class HomeMobilePage extends StatelessWidget {
|
class HomeMobilePage extends StatelessWidget {
|
||||||
HomeMobilePage({super.key});
|
HomeMobilePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Size size = MediaQuery.of(context).size;
|
Size size = MediaQuery.of(context).size;
|
||||||
@ -79,7 +80,7 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic homeItems = [
|
final dynamic homeItems = [
|
||||||
{
|
{
|
||||||
'title': 'Access',
|
'title': 'Access',
|
||||||
'icon': Assets.accessIcon,
|
'icon': Assets.accessIcon,
|
||||||
|
@ -184,6 +184,7 @@ class AddDeviceDialog extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
withCheckBox: true,
|
withCheckBox: true,
|
||||||
size: size * 0.5,
|
size: size * 0.5,
|
||||||
|
uuidIndex: 1,
|
||||||
headers: const [
|
headers: const [
|
||||||
'Device Name',
|
'Device Name',
|
||||||
'Device ID',
|
'Device ID',
|
||||||
|
@ -15,13 +15,14 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
bool isSmallScreen = isSmallScreenSize(context);
|
bool isSmallScreen = isSmallScreenSize(context);
|
||||||
|
bool isHalfMediumScreen = isHafMediumScreenSize(context);
|
||||||
return BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
return BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
||||||
|
final user = context.read<HomeBloc>().user;
|
||||||
return Container(
|
return Container(
|
||||||
height: isSmallScreen ? 130 : 100,
|
height: (isSmallScreen || isHalfMediumScreen) ? 130 : 100,
|
||||||
decoration: const BoxDecoration(color: ColorsManager.secondaryColor),
|
decoration: const BoxDecoration(color: ColorsManager.secondaryColor),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: isSmallScreen
|
child: isSmallScreen || isHalfMediumScreen
|
||||||
? Column(
|
? Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -31,14 +32,11 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
child: title!,
|
child: title!,
|
||||||
),
|
),
|
||||||
if (centerBody != null)
|
if (centerBody != null)
|
||||||
Align(
|
Padding(
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
child: centerBody,
|
child: centerBody,
|
||||||
),
|
),
|
||||||
),
|
if (rightBody != null || user != null)
|
||||||
if (rightBody != null || HomeBloc.user != null)
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -61,9 +59,9 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
if (HomeBloc.user != null)
|
if (user != null)
|
||||||
Text(
|
Text(
|
||||||
'${HomeBloc.user!.firstName} ${HomeBloc.user!.lastName}',
|
'${user.firstName} ${user.lastName}',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -78,12 +76,17 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
children: [
|
children: [
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: title!,
|
child: Expanded(
|
||||||
),
|
child: Row(
|
||||||
|
children: [
|
||||||
|
title!,
|
||||||
if (centerBody != null)
|
if (centerBody != null)
|
||||||
Expanded(
|
Padding(
|
||||||
child: Center(
|
padding: const EdgeInsets.only(left: 80),
|
||||||
child: centerBody,
|
child: centerBody!,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
@ -113,9 +116,9 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
if (HomeBloc.user != null)
|
if (user != null)
|
||||||
Text(
|
Text(
|
||||||
'${HomeBloc.user!.firstName} ${HomeBloc.user!.lastName}',
|
'${user.firstName} ${user.lastName}',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
Reference in New Issue
Block a user