adding tabs and create widget

This commit is contained in:
ashrafzarkanisala
2024-11-13 12:09:31 +03:00
parent d3e758ef3a
commit a6e2681b6a
12 changed files with 252 additions and 81 deletions

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';

View File

@ -0,0 +1,28 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part 'switch_tabs_event.dart';
part 'switch_tabs_state.dart';
class SwitchTabsBloc extends Bloc<SwitchTabsEvent, SwitchTabsState> {
SwitchTabsBloc() : super(SwitchTabsInitial()) {
on<TriggerSwitchTabsEvent>(_switchTab);
on<CreateNewRoutineViewEvent>(_newRoutineView);
}
FutureOr<void> _switchTab(
TriggerSwitchTabsEvent event,
Emitter<SwitchTabsState> emit,
) {
emit(SelectedTabState(event.isRoutineView));
}
FutureOr<void> _newRoutineView(
CreateNewRoutineViewEvent event,
Emitter<SwitchTabsState> emit,
) {
emit(ShowCreateRoutineState(event.showCreateNewRoutineView));
}
}

View File

@ -0,0 +1,21 @@
part of 'switch_tabs_bloc.dart';
sealed class SwitchTabsEvent extends Equatable {
const SwitchTabsEvent();
}
class TriggerSwitchTabsEvent extends SwitchTabsEvent {
final bool isRoutineView;
const TriggerSwitchTabsEvent(this.isRoutineView);
@override
List<Object?> get props => [isRoutineView];
}
class CreateNewRoutineViewEvent extends SwitchTabsEvent {
final bool showCreateNewRoutineView;
const CreateNewRoutineViewEvent(this.showCreateNewRoutineView);
@override
List<Object?> get props => [showCreateNewRoutineView];
}

View File

@ -0,0 +1,26 @@
part of 'switch_tabs_bloc.dart';
sealed class SwitchTabsState extends Equatable {
const SwitchTabsState();
}
final class SwitchTabsInitial extends SwitchTabsState {
@override
List<Object> get props => [];
}
class SelectedTabState extends SwitchTabsState {
final bool selectedTab;
const SelectedTabState(this.selectedTab);
@override
List<Object?> get props => [selectedTab];
}
class ShowCreateRoutineState extends SwitchTabsState {
final bool showCreateRoutine;
const ShowCreateRoutineState(this.showCreateRoutine);
@override
List<Object?> get props => [showCreateRoutine];
}

View File

@ -1,18 +1,30 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart'; import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart'; import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
import 'package:syncrow_web/pages/routiens/view/routines_view.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.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';
import 'package:syncrow_web/web_layout/web_scaffold.dart';
class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
const DeviceManagementPage({super.key}); const DeviceManagementPage({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => DeviceManagementBloc()..add(FetchDevices()), create: (context) => DeviceManagementBloc()..add(FetchDevices()),
),
BlocProvider(
create: (context) => SwitchTabsBloc()..add(const TriggerSwitchTabsEvent(false)),
),
],
child: WebScaffold( child: WebScaffold(
appBarTitle: FittedBox( appBarTitle: FittedBox(
child: Text( child: Text(
@ -20,26 +32,74 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
style: Theme.of(context).textTheme.headlineLarge, style: Theme.of(context).textTheme.headlineLarge,
), ),
), ),
centerBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(builder: (context, state) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
style: TextButton.styleFrom(
backgroundColor: null,
),
onPressed: () {
context.read<SwitchTabsBloc>().add(const TriggerSwitchTabsEvent(false));
},
child: Text(
'Devices',
style: context.textTheme.titleMedium?.copyWith(
color: state is SelectedTabState && state.selectedTab == false
? ColorsManager.whiteColors
: ColorsManager.grayColor,
fontWeight:
(state is SelectedTabState) && state.selectedTab == false ? FontWeight.w700 : FontWeight.w400,
),
),
),
TextButton(
style: TextButton.styleFrom(
backgroundColor: null,
),
onPressed: () {
context.read<SwitchTabsBloc>().add(const TriggerSwitchTabsEvent(true));
},
child: Text(
'Routines',
style: context.textTheme.titleMedium?.copyWith(
color: (state is SelectedTabState) && state.selectedTab == true
? ColorsManager.whiteColors
: ColorsManager.grayColor,
fontWeight:
(state is SelectedTabState) && state.selectedTab == true ? FontWeight.w700 : FontWeight.w400,
),
),
),
],
);
}),
rightBody: const NavigateHomeGridView(), rightBody: const NavigateHomeGridView(),
scaffoldBody: BlocBuilder<DeviceManagementBloc, DeviceManagementState>( scaffoldBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(builder: (context, state) {
builder: (context, state) { if (state is SelectedTabState && state.selectedTab) {
if (state is DeviceManagementLoading) { return const RoutinesView();
}
if (state is ShowCreateRoutineState && state.showCreateRoutine) {
return const CreateNewRoutineView();
}
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
builder: (context, deviceState) {
if (deviceState is DeviceManagementLoading) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (state is DeviceManagementLoaded || state is DeviceManagementFiltered) { } else if (deviceState is DeviceManagementLoaded || deviceState is DeviceManagementFiltered) {
final devices = state is DeviceManagementLoaded final devices =
? state.devices (deviceState as dynamic).devices ?? (deviceState as DeviceManagementFiltered).filteredDevices;
: (state as DeviceManagementFiltered).filteredDevices;
return DeviceManagementBody(devices: devices); return DeviceManagementBody(devices: devices);
} else { } else {
return const Center(child: Text('Error fetching Devices')); return const Center(child: Text('Error fetching Devices'));
} }
}, },
), );
}),
), ),
); );
} }
} }

View File

@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/custom_table.dart';
import 'package:syncrow_web/pages/common/filter/filter_widget.dart'; import 'package:syncrow_web/pages/common/filter/filter_widget.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart'; import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
@ -57,15 +57,12 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
'Low Battery ($lowBatteryCount)', 'Low Battery ($lowBatteryCount)',
]; ];
final buttonLabel = final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
(selectedDevices.length > 1) ? 'Batch Control' : 'Control';
return Column( return Column(
children: [ children: [
Container( Container(
padding: isLargeScreenSize(context) padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
? const EdgeInsets.all(30)
: const EdgeInsets.all(15),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -74,9 +71,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
tabs: tabs, tabs: tabs,
selectedIndex: selectedIndex, selectedIndex: selectedIndex,
onTabChanged: (index) { onTabChanged: (index) {
context context.read<DeviceManagementBloc>().add(SelectedFilterChanged(index));
.read<DeviceManagementBloc>()
.add(SelectedFilterChanged(index));
}, },
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
@ -98,14 +93,11 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
), ),
); );
} else if (selectedDevices.length > 1) { } else if (selectedDevices.length > 1) {
final productTypes = selectedDevices final productTypes = selectedDevices.map((device) => device.productType).toSet();
.map((device) => device.productType)
.toSet();
if (productTypes.length == 1) { if (productTypes.length == 1) {
showDialog( showDialog(
context: context, context: context,
builder: (context) => builder: (context) => DeviceBatchControlDialog(
DeviceBatchControlDialog(
devices: selectedDevices, devices: selectedDevices,
), ),
); );
@ -119,9 +111,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: isControlButtonEnabled color: isControlButtonEnabled ? Colors.white : Colors.grey,
? Colors.white
: Colors.grey,
), ),
), ),
), ),
@ -132,17 +122,13 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: isLargeScreenSize(context) padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
? const EdgeInsets.all(30)
: const EdgeInsets.all(15),
child: DynamicTable( child: DynamicTable(
withSelectAll: true, withSelectAll: true,
cellDecoration: containerDecoration, cellDecoration: containerDecoration,
onRowSelected: (index, isSelected, row) { onRowSelected: (index, isSelected, row) {
final selectedDevice = devicesToShow[index]; final selectedDevice = devicesToShow[index];
context context.read<DeviceManagementBloc>().add(SelectDevice(selectedDevice));
.read<DeviceManagementBloc>()
.add(SelectDevice(selectedDevice));
}, },
withCheckBox: true, withCheckBox: true,
size: MediaQuery.of(context).size, size: MediaQuery.of(context).size,
@ -160,44 +146,27 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
], ],
data: devicesToShow.map((device) { data: devicesToShow.map((device) {
final combinedSpaceNames = device.spaces != null final combinedSpaceNames = device.spaces != null
? device.spaces! ? device.spaces!.map((space) => space.spaceName).join(' > ') +
.map((space) => space.spaceName) (device.community != null ? ' > ${device.community!.name}' : '')
.join(' > ') + : (device.community != null ? device.community!.name : '');
(device.community != null
? ' > ${device.community!.name}'
: '')
: (device.community != null
? device.community!.name
: '');
return [ return [
device.name ?? '', device.name ?? '',
device.productName ?? '', device.productName ?? '',
device.uuid ?? '', device.uuid ?? '',
(device.spaces != null && device.spaces!.isNotEmpty) (device.spaces != null && device.spaces!.isNotEmpty) ? device.spaces![0].spaceName : '',
? device.spaces![0].spaceName
: '',
combinedSpaceNames, combinedSpaceNames,
device.batteryLevel != null device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
? '${device.batteryLevel}%' formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
: '-',
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
(device.createTime ?? 0) * 1000)),
device.online == true ? 'Online' : 'Offline', device.online == true ? 'Online' : 'Offline',
formatDateTime(DateTime.fromMillisecondsSinceEpoch( formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
(device.updateTime ?? 0) * 1000)),
]; ];
}).toList(), }).toList(),
onSelectionChanged: (selectedRows) { onSelectionChanged: (selectedRows) {
context context.read<DeviceManagementBloc>().add(UpdateSelection(selectedRows));
.read<DeviceManagementBloc>()
.add(UpdateSelection(selectedRows));
}, },
initialSelectedIds: context initialSelectedIds:
.read<DeviceManagementBloc>() context.read<DeviceManagementBloc>().selectedDevices.map((device) => device.uuid!).toList(),
.selectedDevices
.map((device) => device.uuid!)
.toList(),
isEmpty: devicesToShow.isEmpty, isEmpty: devicesToShow.isEmpty,
), ),
), ),

View File

@ -1,10 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart'; import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.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';
import 'package:syncrow_web/utils/style.dart';
class DeviceSearchFilters extends StatefulWidget { class DeviceSearchFilters extends StatefulWidget {
const DeviceSearchFilters({super.key}); const DeviceSearchFilters({super.key});
@ -13,8 +12,7 @@ class DeviceSearchFilters extends StatefulWidget {
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState(); State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
} }
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
with HelperResponsiveLayout {
final TextEditingController communityController = TextEditingController(); final TextEditingController communityController = TextEditingController();
final TextEditingController unitNameController = TextEditingController(); final TextEditingController unitNameController = TextEditingController();
final TextEditingController productNameController = TextEditingController(); final TextEditingController productNameController = TextEditingController();
@ -36,8 +34,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchField("Space Name", unitNameController, 200), _buildSearchField("Space Name", unitNameController, 200),
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchField( _buildSearchField("Device Name / Product Name", productNameController, 300),
"Device Name / Product Name", productNameController, 300),
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchResetButtons(), _buildSearchResetButtons(),
], ],
@ -62,8 +59,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
); );
} }
Widget _buildSearchField( Widget _buildSearchField(String title, TextEditingController controller, double width) {
String title, TextEditingController controller, double width) {
return Container( return Container(
child: StatefulTextField( child: StatefulTextField(
title: title, title: title,

View File

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class CreateNewRoutineView extends StatelessWidget {
const CreateNewRoutineView({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View File

@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class RoutinesView extends StatelessWidget {
const RoutinesView({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Create New Routines",
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: ColorsManager.grayColor,
)),
SizedBox(
height: 200,
width: 150,
child: GestureDetector(
onTap: () {
BlocProvider.of<SwitchTabsBloc>(context).add(
const CreateNewRoutineViewEvent(true),
);
},
child: Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
color: ColorsManager.whiteColors,
child: Center(
child: Container(
decoration: BoxDecoration(
color: ColorsManager.graysColor,
borderRadius: BorderRadius.circular(120),
border: Border.all(color: ColorsManager.greyColor, width: 2.0),
),
height: 70,
width: 70,
child: Icon(
Icons.add,
color: ColorsManager.dialogBlueTitle,
size: 40,
),
)),
),
),
),
const Spacer(),
],
),
);
}
}