diff --git a/lib/common/widgets/search_bar.dart b/lib/common/widgets/search_bar.dart index 728fad33..9d17d1c1 100644 --- a/lib/common/widgets/search_bar.dart +++ b/lib/common/widgets/search_bar.dart @@ -46,14 +46,13 @@ class CustomSearchBar extends StatelessWidget { filled: true, fillColor: ColorsManager.textFieldGreyColor, hintText: hintText, - hintStyle: TextStyle( - color: Color(0xB2999999), - fontSize: 12, - fontFamily: 'Aftika', - fontWeight: FontWeight.w400, - height: 0, - letterSpacing: -0.24, - ), + hintStyle: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: ColorsManager.lightGrayColor, + fontSize: 12, + fontWeight: FontWeight.w400, + height: 0, + letterSpacing: -0.24, + ), suffixIcon: Padding( padding: const EdgeInsets.only(right: 16), child: SvgPicture.asset( diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index af4e8039..d97972d4 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -8,7 +8,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo 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_control_dialog.dart'; -import 'package:syncrow_web/pages/space_tree/view/side_spaces_view.dart'; +import 'package:syncrow_web/pages/space_tree/view/side_tree_view.dart'; import 'package:syncrow_web/utils/format_date_time.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/style.dart'; @@ -62,12 +62,13 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { return Row( children: [ - Flexible(child: SideSpacesView( - onSelectAction: (String communityId, String spaceId) { - context.read().add(FetchDevices(communityId, spaceId)); - }, - )), - Flexible( + const Expanded( + child: SideTreeView( + // onSelectAction: (String communityId, String spaceId) { + // context.read().add(FetchDevices(communityId, spaceId)); + // }, + )), + Expanded( flex: 3, child: state is DeviceManagementLoading ? const Center(child: CircularProgressIndicator()) diff --git a/lib/pages/home/view/home_page_web.dart b/lib/pages/home/view/home_page_web.dart index 3e4ad932..2b7b5d95 100644 --- a/lib/pages/home/view/home_page_web.dart +++ b/lib/pages/home/view/home_page_web.dart @@ -82,7 +82,7 @@ class HomeWebPage extends StatelessWidget { child: GridView.builder( itemCount: 3, //8 gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, + crossAxisCount: 3, //4 crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, childAspectRatio: 1.5, diff --git a/lib/pages/routines/view/routines_view.dart b/lib/pages/routines/view/routines_view.dart index f1befb05..e7601729 100644 --- a/lib/pages/routines/view/routines_view.dart +++ b/lib/pages/routines/view/routines_view.dart @@ -5,7 +5,7 @@ import 'package:syncrow_web/pages/routines/view/create_new_routine_view.dart'; import 'package:syncrow_web/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart'; import 'package:syncrow_web/pages/routines/widgets/main_routine_view/routine_view_card.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; -import 'package:syncrow_web/pages/space_tree/view/side_spaces_view.dart'; +import 'package:syncrow_web/pages/space_tree/view/side_tree_view.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; @@ -32,13 +32,16 @@ class _RoutinesViewState extends State { } return Row( children: [ - Expanded(child: SideSpacesView( - onSelectAction: (String communityId, String spaceId) { - context.read() - ..add(LoadScenes(spaceId, communityId)) - ..add(LoadAutomation(spaceId)); - }, - )), + const Expanded( + child: + // SideSpacesView( + // onSelectAction: (String communityId, String spaceId) { + // // context.read() + // // ..add(LoadScenes(spaceId, communityId)) + // // ..add(LoadAutomation(spaceId)); + // }, + // ) + SideTreeView()), Expanded( flex: 3, child: Padding( diff --git a/lib/pages/space_tree/bloc/space_tree_bloc.dart b/lib/pages/space_tree/bloc/space_tree_bloc.dart index 41b0d6b0..78da9fd2 100644 --- a/lib/pages/space_tree/bloc/space_tree_bloc.dart +++ b/lib/pages/space_tree/bloc/space_tree_bloc.dart @@ -8,21 +8,26 @@ import 'package:syncrow_web/services/space_mana_api.dart'; class SpaceTreeBloc extends Bloc { String selectedCommunityId = ''; String selectedSpaceId = ''; + SpaceTreeBloc() : super(const SpaceTreeState()) { on(_fetchSpaces); - on(_onSelectSpace); + on(_onCommunityExpanded); + on(_onSpaceExpanded); + on(_onCommunitySelected); + on(_onSpaceSelected); + on(_onSearch); } _fetchSpaces(InitialEvent event, Emitter emit) async { emit(SpaceTreeLoadingState()); try { - // _onloadProducts(); List communities = await CommunitySpaceManagementApi().fetchCommunities(); List updatedCommunities = await Future.wait( communities.map((community) async { List spaces = await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid); + return CommunityModel( uuid: community.uuid, createdAt: community.createdAt, @@ -35,35 +40,170 @@ class SpaceTreeBloc extends Bloc { }).toList(), ); - if (updatedCommunities.isNotEmpty && - state.selectedSpace.isEmpty && - state.selectedCommunity.isEmpty) { - selectedCommunityId = updatedCommunities[0].uuid; - } else { - selectedCommunityId = state.selectedCommunity; - selectedSpaceId = state.selectedSpace; - } - emit(state.copyWith( - communitiesList: updatedCommunities, - selectedCommunity: selectedCommunityId, - selectedSpace: selectedSpaceId)); + communitiesList: updatedCommunities, expandedCommunity: [], expandedSpaces: [])); } catch (e) { emit(SpaceTreeErrorState('Error loading communities and spaces: $e')); } } - _onSelectSpace(OnSelectSpaceEvent event, Emitter emit) async { + _onCommunityExpanded(OnCommunityExpanded event, Emitter emit) async { try { - selectedCommunityId = event.communityId; - selectedSpaceId = event.spaceId; + List updatedExpandedCommunityList = List.from(state.expandedCommunities); + + if (updatedExpandedCommunityList.contains(event.communityId)) { + updatedExpandedCommunityList.remove(event.communityId); + } else { + updatedExpandedCommunityList.add(event.communityId); + } emit(state.copyWith( - communitiesList: state.spacesList, - selectedCommunity: event.communityId, - selectedSpace: event.spaceId)); + expandedCommunity: updatedExpandedCommunityList, + )); } catch (e) { emit(const SpaceTreeErrorState('Something went wrong')); } } + + _onSpaceExpanded(OnSpaceExpanded event, Emitter emit) async { + try { + List updatedExpandedSpacesList = List.from(state.expandedSpaces); + + if (updatedExpandedSpacesList.contains(event.spaceId)) { + updatedExpandedSpacesList.remove(event.spaceId); + } else { + updatedExpandedSpacesList.add(event.spaceId); + } + + emit(state.copyWith(expandedSpaces: updatedExpandedSpacesList)); + } catch (e) { + emit(const SpaceTreeErrorState('Something went wrong')); + } + } + + _onCommunitySelected(OnCommunitySelected event, Emitter emit) async { + try { + List updatedSelectedCommunities = List.from(state.selectedCommunities); + List updatedSelectedSpaces = List.from(state.selectedSpaces); + List updatedSoldChecks = List.from(state.soldCheck); + + List childrenIds = _getAllChildIds(event.children); + + if (!updatedSelectedCommunities.contains(event.communityId)) { + // Select the community and all its children + updatedSelectedCommunities.add(event.communityId); + updatedSelectedSpaces.addAll(childrenIds); + } else { + // Unselect the community and all its children + updatedSelectedCommunities.remove(event.communityId); + updatedSelectedSpaces.removeWhere(childrenIds.contains); + updatedSoldChecks.removeWhere(childrenIds.contains); + } + + emit(state.copyWith( + selectedCommunities: updatedSelectedCommunities, + selectedSpaces: updatedSelectedSpaces, + soldCheck: updatedSoldChecks)); + } catch (e) { + emit(const SpaceTreeErrorState('Something went wrong')); + } + } + + _onSpaceSelected(OnSpaceSelected event, Emitter emit) async { + try { + List updatedSelectedCommunities = List.from(state.selectedCommunities); + List updatedSelectedSpaces = List.from(state.selectedSpaces); + List updatedSoldChecks = List.from(state.soldCheck); + + List childrenIds = _getAllChildIds(event.children); + + // List childrenIds = _getAllChildSpaceIds(event.communityId); + + if (!updatedSelectedSpaces.contains(event.spaceId) && + !updatedSoldChecks.contains(event.spaceId)) { + // First click: Select the space and all its children + updatedSelectedSpaces.add(event.spaceId); + updatedSelectedCommunities.add(event.communityId); + if (childrenIds.isNotEmpty) { + updatedSelectedSpaces.addAll(childrenIds); + } + } else if (!updatedSoldChecks.contains(event.spaceId) && childrenIds.isNotEmpty) { + // Second click: Unselect space but keep children + updatedSelectedSpaces.remove(event.spaceId); + updatedSoldChecks.add(event.spaceId); + } else { + // Third click: Unselect space and all its children + if (!_anySpacesSelectedInCommunity(event.communityId)) { + updatedSelectedCommunities.remove(event.communityId); + } + updatedSelectedSpaces.remove(event.spaceId); + if (childrenIds.isNotEmpty) { + updatedSelectedSpaces.removeWhere(childrenIds.contains); + } + updatedSoldChecks.remove(event.spaceId); + } + + emit(state.copyWith( + selectedCommunities: updatedSelectedCommunities, + selectedSpaces: updatedSelectedSpaces, + soldCheck: updatedSoldChecks)); + emit(state.copyWith(selectedSpaces: updatedSelectedSpaces)); + } catch (e) { + emit(const SpaceTreeErrorState('Something went wrong')); + } + } + + _onSearch(SearchQueryEvent event, Emitter emit) async { + try { + List communities = List.from(state.communityList); + List filteredCommunity = []; + + // Filter communities and expand only those that match the query + filteredCommunity = communities.where((community) { + final containsQueryInCommunity = + community.name.toLowerCase().contains(event.searchQuery.toLowerCase()); + final containsQueryInSpaces = + community.spaces.any((space) => _containsQuery(space, event.searchQuery.toLowerCase())); + + return containsQueryInCommunity || containsQueryInSpaces; + }).toList(); + + emit(state.copyWith( + filteredCommunity: filteredCommunity, isSearching: event.searchQuery.isNotEmpty)); + } catch (e) { + emit(const SpaceTreeErrorState('Something went wrong')); + } + } + + // Helper function to determine if any space or its children match the search query + bool _containsQuery(SpaceModel space, String query) { + final matchesSpace = space.name.toLowerCase().contains(query); + final matchesChildren = + space.children.any((child) => _containsQuery(child, query)); // Recursive check for children + + return matchesSpace || matchesChildren; + } + + List _getAllChildIds(List spaces) { + List ids = []; + for (var child in spaces) { + ids.add(child.uuid!); + ids.addAll(_getAllChildIds(child.children)); + } + return ids; + } + + bool _anySpacesSelectedInCommunity(String communityId) { + bool result = false; + for (var community in state.communityList) { + if (community.uuid == communityId) { + List ids = _getAllChildIds(community.spaces); + for (var id in ids) { + result = state.selectedSpaces.contains(id); + break; + } + } + } + return result; + } } diff --git a/lib/pages/space_tree/bloc/space_tree_event.dart b/lib/pages/space_tree/bloc/space_tree_event.dart index d6c95579..7b1b550c 100644 --- a/lib/pages/space_tree/bloc/space_tree_event.dart +++ b/lib/pages/space_tree/bloc/space_tree_event.dart @@ -1,4 +1,5 @@ import 'package:equatable/equatable.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; class SpaceTreeEvent extends Equatable { const SpaceTreeEvent(); @@ -9,16 +10,6 @@ class SpaceTreeEvent extends Equatable { class InitialEvent extends SpaceTreeEvent {} -class OnSelectSpaceEvent extends SpaceTreeEvent { - final String communityId; - final String spaceId; - - const OnSelectSpaceEvent(this.communityId, this.spaceId); - - @override - List get props => [communityId, spaceId]; -} - class SearchForSpace extends SpaceTreeEvent { final String searchQuery; @@ -27,3 +18,52 @@ class SearchForSpace extends SpaceTreeEvent { @override List get props => [searchQuery]; } + +class OnCommunityExpanded extends SpaceTreeEvent { + final String communityId; + + const OnCommunityExpanded(this.communityId); + + @override + List get props => [communityId]; +} + +class OnCommunitySelected extends SpaceTreeEvent { + final String communityId; + final List children; + + const OnCommunitySelected(this.communityId, this.children); + + @override + List get props => [communityId, children]; +} + +class OnSpaceExpanded extends SpaceTreeEvent { + final String communityId; + final String spaceId; + + const OnSpaceExpanded(this.communityId, this.spaceId); + + @override + List get props => [communityId, spaceId]; +} + +class OnSpaceSelected extends SpaceTreeEvent { + final String communityId; + final String spaceId; + final List children; + + const OnSpaceSelected(this.communityId, this.spaceId, this.children); + + @override + List get props => [communityId, spaceId, children]; +} + +class SearchQueryEvent extends SpaceTreeEvent { + final String searchQuery; + + const SearchQueryEvent(this.searchQuery); + + @override + List get props => [searchQuery]; +} diff --git a/lib/pages/space_tree/bloc/space_tree_state.dart b/lib/pages/space_tree/bloc/space_tree_state.dart index ab82f2dc..b5c987ef 100644 --- a/lib/pages/space_tree/bloc/space_tree_state.dart +++ b/lib/pages/space_tree/bloc/space_tree_state.dart @@ -2,23 +2,56 @@ import 'package:equatable/equatable.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; class SpaceTreeState extends Equatable { - final List spacesList; - final String selectedSpace; - final String selectedCommunity; + final List communityList; + final List filteredCommunity; + final List expandedCommunities; + final List expandedSpaces; + final List selectedCommunities; + final List selectedSpaces; + final List soldCheck; + final bool isSearching; const SpaceTreeState( - {this.spacesList = const [], this.selectedSpace = '', this.selectedCommunity = ''}); + {this.communityList = const [], + this.filteredCommunity = const [], + this.expandedCommunities = const [], + this.expandedSpaces = const [], + this.selectedCommunities = const [], + this.selectedSpaces = const [], + this.soldCheck = const [], + this.isSearching = false}); SpaceTreeState copyWith( - {List? communitiesList, String? selectedSpace, String? selectedCommunity}) { + {List? communitiesList, + List? filteredCommunity, + List? expandedSpaces, + List? expandedCommunity, + List? selectedCommunities, + List? selectedSpaces, + List? soldCheck, + bool? isSearching}) { return SpaceTreeState( - spacesList: communitiesList ?? this.spacesList, - selectedSpace: selectedSpace ?? this.selectedSpace, - selectedCommunity: selectedCommunity ?? this.selectedCommunity); + communityList: communitiesList ?? this.communityList, + filteredCommunity: filteredCommunity ?? this.filteredCommunity, + expandedSpaces: expandedSpaces ?? this.expandedSpaces, + expandedCommunities: expandedCommunity ?? this.expandedCommunities, + selectedCommunities: selectedCommunities ?? this.selectedCommunities, + selectedSpaces: selectedSpaces ?? this.selectedSpaces, + soldCheck: soldCheck ?? this.soldCheck, + isSearching: isSearching ?? this.isSearching); } @override - List get props => [spacesList, selectedSpace, selectedCommunity]; + List get props => [ + communityList, + filteredCommunity, + expandedSpaces, + expandedCommunities, + selectedCommunities, + selectedSpaces, + soldCheck, + isSearching + ]; } class SpaceTreeLoadingState extends SpaceTreeState {} @@ -26,6 +59,7 @@ class SpaceTreeLoadingState extends SpaceTreeState {} class SpaceTreeErrorState extends SpaceTreeState { final String message; const SpaceTreeErrorState(this.message); + @override List get props => [message]; } diff --git a/lib/pages/space_tree/view/community_tile.dart b/lib/pages/space_tree/view/community_tile.dart deleted file mode 100644 index 938aa682..00000000 --- a/lib/pages/space_tree/view/community_tile.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:syncrow_web/pages/space_tree/view/custom_expansion.dart'; - -class CommunityTileSpaceTree extends StatelessWidget { - final String title; - final List? children; - final bool isExpanded; - final bool isSelected; - final Function(String, bool) onExpansionChanged; - final Function() onItemSelected; - - const CommunityTileSpaceTree({ - super.key, - required this.title, - required this.isExpanded, - required this.onExpansionChanged, - required this.onItemSelected, - required this.isSelected, - this.children, - }); - - @override - Widget build(BuildContext context) { - return CustomExpansionTileSpaceTree( - title: title, - initiallyExpanded: isExpanded, - isSelected: isSelected, - onExpansionChanged: (bool expanded) { - onExpansionChanged(title, expanded); - }, - onItemSelected: onItemSelected, - children: children ?? [], - ); - } -} diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index 7314417b..9e40f320 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -1,54 +1,26 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/utils/color_manager.dart'; -class CustomExpansionTileSpaceTree extends StatefulWidget { +class CustomExpansionTileSpaceTree extends StatelessWidget { + final String? spaceId; final String title; final List? children; - final bool initiallyExpanded; - final bool isSelected; // Add this to track selection - final bool? isExpanded; // External control over expansion - final ValueChanged? onExpansionChanged; // Notify when expansion changes - final VoidCallback? onItemSelected; // Callback for selecting the item + final bool isSelected; + final bool isSoldCheck; + final bool isExpanded; + final Function? onExpansionChanged; + final Function? onItemSelected; - CustomExpansionTileSpaceTree({ - required this.title, - this.children, - this.initiallyExpanded = false, - this.isExpanded, // Allow external control over expansion - this.onExpansionChanged, // Notify when expansion changes - this.onItemSelected, // Trigger item selection when name is tapped - required this.isSelected, // Add this to initialize selection state - }); - - @override - CustomExpansionTileState createState() => CustomExpansionTileState(); -} - -class CustomExpansionTileState extends State { - bool _isExpanded = false; // Local expansion state - - @override - void initState() { - super.initState(); - _isExpanded = widget.initiallyExpanded; - } - - @override - void didUpdateWidget(CustomExpansionTileSpaceTree oldWidget) { - super.didUpdateWidget(oldWidget); - // Sync local state with external control of expansion state - if (widget.isExpanded != null && widget.isExpanded != _isExpanded) { - setState(() { - _isExpanded = widget.isExpanded!; - }); - } - } - - // Utility function to capitalize the first letter of the title - String _capitalizeFirstLetter(String text) { - if (text.isEmpty) return text; - return text[0].toUpperCase() + text.substring(1); - } + const CustomExpansionTileSpaceTree( + {super.key, + this.spaceId, + required this.title, + this.children, + this.isExpanded = false, + this.onExpansionChanged, + this.onItemSelected, + required this.isSelected, + this.isSoldCheck = false}); @override Widget build(BuildContext context) { @@ -56,14 +28,14 @@ class CustomExpansionTileState extends State { children: [ Row( children: [ - // Checkbox with independent state management Checkbox( - value: widget.isSelected, + value: isSoldCheck ? null : isSelected, onChanged: (bool? value) { - if (widget.onItemSelected != null) { - widget.onItemSelected!(); + if (onItemSelected != null) { + onItemSelected!(); } }, + tristate: true, side: WidgetStateBorderSide.resolveWith((states) { return const BorderSide(color: ColorsManager.grayBorder); }), @@ -76,52 +48,52 @@ class CustomExpansionTileState extends State { }), checkColor: ColorsManager.whiteColors, ), - // Expand/collapse icon, now wrapped in a GestureDetector for specific onTap - if (widget.children != null && widget.children!.isNotEmpty) - GestureDetector( + if (children != null && children!.isNotEmpty) + InkWell( onTap: () { - setState(() { - _isExpanded = !_isExpanded; - widget.onExpansionChanged?.call(_isExpanded); - }); + if (onExpansionChanged != null) { + onExpansionChanged!(); + } }, child: Icon( - _isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right, + isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right, color: ColorsManager.lightGrayColor, - size: 16.0, // Adjusted size for better alignment + size: 16.0, ), ), - // The title text, wrapped in GestureDetector to handle selection Expanded( child: GestureDetector( onTap: () { - if (widget.onItemSelected != null) { - widget.onItemSelected!(); + if (onItemSelected != null) { + onItemSelected!(); } }, child: Text( - _capitalizeFirstLetter(widget.title), - style: TextStyle( - color: widget.isSelected - ? ColorsManager.blackColor // Change color to black when selected - : ColorsManager.lightGrayColor, // Gray when not selected - fontWeight: FontWeight.w400, - ), + _capitalizeFirstLetter(title), + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: isSelected + ? ColorsManager.blackColor // Change color to black when selected + : ColorsManager.lightGrayColor, // Gray when not selected + fontWeight: FontWeight.w400, + ), ), ), ), ], ), - // The expanded section (children) that shows when the tile is expanded - if (_isExpanded && widget.children != null && widget.children!.isNotEmpty) + if (isExpanded && children != null && children!.isNotEmpty) Padding( - padding: const EdgeInsets.only(left: 48.0), // Indented children + padding: const EdgeInsets.only(left: 48.0), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: widget.children!, + children: children ?? [], ), ), ], ); } + + String _capitalizeFirstLetter(String text) { + if (text.isEmpty) return text; + return text[0].toUpperCase() + text.substring(1); + } } diff --git a/lib/pages/space_tree/view/side_spaces_view.dart b/lib/pages/space_tree/view/side_spaces_view.dart deleted file mode 100644 index c890ef69..00000000 --- a/lib/pages/space_tree/view/side_spaces_view.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; -import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart'; -import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; - -class SideSpacesView extends StatelessWidget { - final Function onSelectAction; - const SideSpacesView({required this.onSelectAction, super.key}); - - @override - Widget build(BuildContext context) { - return BlocConsumer( - listener: (context, state) {}, - builder: (context, state) { - return SpaceTreeView( - communities: state.spacesList, - selectedSpaceUuid: state.selectedSpace, - selectedCommunityId: state.selectedCommunity, - buildContext: context, - action: onSelectAction, - isLoading: state is SpaceTreeLoadingState, - ); - }); - } -} diff --git a/lib/pages/space_tree/view/side_tree_view.dart b/lib/pages/space_tree/view/side_tree_view.dart new file mode 100644 index 00000000..4725d09b --- /dev/null +++ b/lib/pages/space_tree/view/side_tree_view.dart @@ -0,0 +1,120 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/common/widgets/search_bar.dart'; +import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; +import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; +import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart'; +import 'package:syncrow_web/pages/space_tree/view/custom_expansion.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/style.dart'; + +class SideTreeView extends StatelessWidget { + const SideTreeView({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder(builder: (context, state) { + List list = state.isSearching ? state.filteredCommunity : state.communityList; + return Container( + height: MediaQuery.sizeOf(context).height, + decoration: subSectionContainerDecoration, + // padding: const EdgeInsets.all(16.0), + child: state is SpaceTreeLoadingState + ? const Center(child: CircularProgressIndicator()) + : Column( + children: [ + CustomSearchBar( + onSearchChanged: (query) { + context.read().add(SearchQueryEvent(query)); + }, + ), + const SizedBox(height: 16), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: list.isEmpty + ? Center( + child: Text( + 'No results found', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.lightGrayColor, // Gray when not selected + fontWeight: FontWeight.w400, + ), + ), + ) + : ListView( + shrinkWrap: true, + children: list + .map( + (community) => CustomExpansionTileSpaceTree( + title: community.name, + isSelected: + state.selectedCommunities.contains(community.uuid), + isSoldCheck: + state.selectedCommunities.contains(community.uuid), + onExpansionChanged: () { + context + .read() + .add(OnCommunityExpanded(community.uuid)); + }, + isExpanded: + state.expandedCommunities.contains(community.uuid), + onItemSelected: () { + context.read().add( + OnCommunitySelected(community.uuid, community.spaces)); + }, + children: community.spaces.map((space) { + return CustomExpansionTileSpaceTree( + title: space.name, + isExpanded: state.expandedSpaces.contains(space.uuid), + onItemSelected: () { + context.read().add(OnSpaceSelected( + community.uuid, space.uuid ?? '', space.children)); + }, + onExpansionChanged: () { + context.read().add( + OnSpaceExpanded(community.uuid, space.uuid ?? '')); + }, + isSelected: state.selectedSpaces.contains(space.uuid) || + state.soldCheck.contains(space.uuid), + isSoldCheck: state.soldCheck.contains(space.uuid), + children: _buildNestedSpaces( + context, state, space, community.uuid), + ); + }).toList(), + ), + ) + .toList(), + ), + ), + ), + ], + ), + ); + }); + } + + List _buildNestedSpaces( + BuildContext context, SpaceTreeState state, SpaceModel space, String communityId) { + return space.children.map((child) { + return CustomExpansionTileSpaceTree( + isSelected: + state.selectedSpaces.contains(child.uuid) || state.soldCheck.contains(child.uuid), + isSoldCheck: state.soldCheck.contains(child.uuid), + title: child.name, + isExpanded: state.expandedSpaces.contains(child.uuid), + onItemSelected: () { + context + .read() + .add(OnSpaceSelected(communityId, child.uuid ?? '', child.children)); + }, + onExpansionChanged: () { + context.read().add(OnSpaceExpanded(communityId, child.uuid ?? '')); + }, + children: _buildNestedSpaces(context, state, child, communityId), + ); + }).toList(); + } +} diff --git a/lib/pages/space_tree/view/space_tile.dart b/lib/pages/space_tree/view/space_tile.dart deleted file mode 100644 index 12d20629..00000000 --- a/lib/pages/space_tree/view/space_tile.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:syncrow_web/pages/space_tree/view/custom_expansion.dart'; - -class SpaceTileSpaceTree extends StatefulWidget { - final String title; - final bool isSelected; - - final bool initiallyExpanded; - final ValueChanged onExpansionChanged; - final List? children; - final Function() onItemSelected; - - const SpaceTileSpaceTree({ - super.key, - required this.title, - required this.initiallyExpanded, - required this.onExpansionChanged, - required this.onItemSelected, - required this.isSelected, - this.children, - }); - - @override - _SpaceTileState createState() => _SpaceTileState(); -} - -class _SpaceTileState extends State { - late bool _isExpanded; - - @override - void initState() { - super.initState(); - _isExpanded = widget.initiallyExpanded; - } - - @override - Widget build(BuildContext context) { - return CustomExpansionTileSpaceTree( - isSelected: widget.isSelected, - title: widget.title, - initiallyExpanded: _isExpanded, - onItemSelected: widget.onItemSelected, - onExpansionChanged: (bool expanded) { - setState(() { - _isExpanded = expanded; - }); - widget.onExpansionChanged(expanded); - }, - children: widget.children ?? [], - ); - } -} diff --git a/lib/pages/space_tree/view/space_tree_view.dart b/lib/pages/space_tree/view/space_tree_view.dart deleted file mode 100644 index 06e77df0..00000000 --- a/lib/pages/space_tree/view/space_tree_view.dart +++ /dev/null @@ -1,251 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/common/widgets/search_bar.dart'; -import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; -import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; -import 'package:syncrow_web/pages/space_tree/view/community_tile.dart'; -import 'package:syncrow_web/pages/space_tree/view/space_tile.dart'; -import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; -import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; -import 'package:syncrow_web/utils/constants/assets.dart'; -import 'package:syncrow_web/utils/style.dart'; - -class SpaceTreeView extends StatefulWidget { - final List communities; - final String? selectedCommunityId; - final String? selectedSpaceUuid; - final BuildContext buildContext; - final Function action; - final bool isLoading; - - const SpaceTreeView( - {super.key, - this.selectedCommunityId, - required this.communities, - this.selectedSpaceUuid, - required this.buildContext, - required this.action, - required this.isLoading}); - - @override - State createState() => _SpaceTreeViewState(); -} - -class _SpaceTreeViewState extends State { - String _searchQuery = ''; // Track search query - String? _selectedSpaceUuid; - String? _selectedCommunityId; - String? _expandedId; - - @override - void initState() { - super.initState(); - // _selectedId = widget.selectedSpaceUuid; // Initialize with the passed selected space UUID - _selectedCommunityId = widget.selectedCommunityId; - _selectedSpaceUuid = widget.selectedSpaceUuid; - } - - @override - void didUpdateWidget(covariant SpaceTreeView oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.selectedSpaceUuid != oldWidget.selectedSpaceUuid || - widget.selectedCommunityId != oldWidget.selectedCommunityId) { - setState(() { - // _selectedId = widget.selectedSpaceUuid; - _selectedCommunityId = widget.selectedCommunityId; - _selectedSpaceUuid = widget.selectedSpaceUuid; - }); - } - } - - // Function to filter communities based on the search query - List _filterCommunities() { - _expandedId = null; - if (_searchQuery.isEmpty) { - // Reset the selected community and space UUIDs if there's no query - // _selectedSpaceUuid = null; - // _selectedCommunityId = null; - return widget.communities; - } - - // Filter communities and expand only those that match the query - return widget.communities.where((community) { - final containsQueryInCommunity = - community.name.toLowerCase().contains(_searchQuery.toLowerCase()); - final containsQueryInSpaces = - community.spaces.any((space) => _containsQuery(space, _searchQuery.toLowerCase())); - - return containsQueryInCommunity || containsQueryInSpaces; - }).toList(); - } - - // Helper function to determine if any space or its children match the search query - bool _containsQuery(SpaceModel space, String query) { - final matchesSpace = space.name.toLowerCase().contains(query); - final matchesChildren = - space.children.any((child) => _containsQuery(child, query)); // Recursive check for children - - // If the space or any of its children match the query, expand this space - if (matchesSpace || matchesChildren) { - _expandedId = space.uuid; - } - - return matchesSpace || matchesChildren; - } - - bool _isSpaceOrChildSelected(SpaceModel space) { - // Return true if the current space or any of its child spaces is selected - if (_expandedId == space.uuid) { - return true; - } - - // Recursively check if any child spaces match the query - for (var child in space.children) { - if (_isSpaceOrChildSelected(child)) { - return true; - } - } - - return false; - } - - @override - Widget build(BuildContext context) { - final filteredCommunities = _filterCommunities(); - - return Container( - // width: MediaQuery.sizeOf(context).width * 0.25, - height: MediaQuery.sizeOf(context).height, - margin: const EdgeInsets.only(right: 24), - decoration: subSectionContainerDecoration, - child: widget.isLoading - ? const Center(child: CircularProgressIndicator()) - : Column( - mainAxisSize: MainAxisSize.min, // Ensures the Column only takes necessary height - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Communities title with the add button - Container( - decoration: subSectionContainerDecoration, - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('Communities', - style: Theme.of(context).textTheme.titleMedium?.copyWith( - color: Colors.black, - )), - GestureDetector( - onTap: () => _navigateToBlank(context), - child: Container( - width: 30, - height: 30, - decoration: const BoxDecoration( - color: ColorsManager.whiteColors, - shape: BoxShape.circle, - ), - child: Center( - child: SvgPicture.asset( - Assets.roundedAddIcon, - width: 24, - height: 24, - ), - ), - ), - ), - ], - ), - ), - // Search bar - CustomSearchBar( - onSearchChanged: (query) { - setState(() { - _selectedSpaceUuid = null; - _searchQuery = query; - }); - }, - ), - const SizedBox(height: 16), - // Community list - Expanded( - child: ListView( - children: filteredCommunities.map((community) { - return _buildCommunityTile(context, community); - }).toList(), - ), - ), - ], - ), - ); - } - - void _navigateToBlank(BuildContext context) { - setState(() { - // _selectedId = ''; - _selectedSpaceUuid = ''; - }); - // context.read().add( - // NewCommunityEvent(communities: widget.communities), - // ); - } - - Widget _buildCommunityTile(BuildContext context, CommunityModel community) { - bool hasChildren = community.spaces.isNotEmpty; - - return CommunityTileSpaceTree( - title: community.name, - key: ValueKey(community.uuid), - isSelected: _selectedCommunityId == community.uuid, - isExpanded: false, - onItemSelected: () { - setState(() { - _selectedCommunityId = community.uuid; - _selectedSpaceUuid = null; - }); - - widget.buildContext.read().add( - OnSelectSpaceEvent(community.uuid, ''), - ); - - widget.action(community.uuid, ''); - }, - onExpansionChanged: (String title, bool expanded) { - _handleExpansionChange(community.uuid, expanded); - }, - children: hasChildren - ? community.spaces.map((space) => _buildSpaceTile(space, community)).toList() - : null, - ); - } - - Widget _buildSpaceTile(SpaceModel space, CommunityModel community) { - return SpaceTileSpaceTree( - title: space.name, - key: ValueKey(space.uuid), - isSelected: _selectedSpaceUuid == space.uuid, - initiallyExpanded: _isSpaceOrChildSelected(space), - onExpansionChanged: (bool expanded) { - _handleExpansionChange(space.uuid ?? '', expanded); - }, - onItemSelected: () { - setState(() { - _selectedSpaceUuid = space.uuid; - _selectedCommunityId = community.uuid; - }); - - widget.buildContext.read().add( - OnSelectSpaceEvent(community.uuid, space.uuid ?? ''), - ); - - widget.action(community.uuid, space.uuid); - }, - children: space.children.isNotEmpty - ? space.children.map((childSpace) => _buildSpaceTile(childSpace, community)).toList() - : [], - ); - } - - void _handleExpansionChange(String uuid, bool expanded) {} -} diff --git a/lib/services/routines_api.dart b/lib/services/routines_api.dart index 551951ea..aae7c453 100644 --- a/lib/services/routines_api.dart +++ b/lib/services/routines_api.dart @@ -73,7 +73,7 @@ class SceneApi { {showInDevice = false}) async { try { final response = await _httpService.get( - path: ApiEndpoints.getScenes + path: ApiEndpoints.getUnitScenes .replaceAll('{spaceUuid}', spaceId) .replaceAll('{communityUuid}', communityId) .replaceAll('{projectId}', TempConst.projectId),