mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
Implemented the selection behavior of the side tree
This commit is contained in:
@ -46,14 +46,13 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
filled: true,
|
filled: true,
|
||||||
fillColor: ColorsManager.textFieldGreyColor,
|
fillColor: ColorsManager.textFieldGreyColor,
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
hintStyle: TextStyle(
|
hintStyle: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
color: Color(0xB2999999),
|
color: ColorsManager.lightGrayColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontFamily: 'Aftika',
|
fontWeight: FontWeight.w400,
|
||||||
fontWeight: FontWeight.w400,
|
height: 0,
|
||||||
height: 0,
|
letterSpacing: -0.24,
|
||||||
letterSpacing: -0.24,
|
),
|
||||||
),
|
|
||||||
suffixIcon: Padding(
|
suffixIcon: Padding(
|
||||||
padding: const EdgeInsets.only(right: 16),
|
padding: const EdgeInsets.only(right: 16),
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
|
@ -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/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';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/device_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/format_date_time.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';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
@ -62,12 +62,13 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Flexible(child: SideSpacesView(
|
const Expanded(
|
||||||
onSelectAction: (String communityId, String spaceId) {
|
child: SideTreeView(
|
||||||
context.read<DeviceManagementBloc>().add(FetchDevices(communityId, spaceId));
|
// onSelectAction: (String communityId, String spaceId) {
|
||||||
},
|
// context.read<DeviceManagementBloc>().add(FetchDevices(communityId, spaceId));
|
||||||
)),
|
// },
|
||||||
Flexible(
|
)),
|
||||||
|
Expanded(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
child: state is DeviceManagementLoading
|
child: state is DeviceManagementLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
@ -82,7 +82,7 @@ class HomeWebPage extends StatelessWidget {
|
|||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
itemCount: 3, //8
|
itemCount: 3, //8
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 4,
|
crossAxisCount: 3, //4
|
||||||
crossAxisSpacing: 20.0,
|
crossAxisSpacing: 20.0,
|
||||||
mainAxisSpacing: 20.0,
|
mainAxisSpacing: 20.0,
|
||||||
childAspectRatio: 1.5,
|
childAspectRatio: 1.5,
|
||||||
|
@ -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/fetch_routine_scenes_automation.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/main_routine_view/routine_view_card.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/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/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||||
|
|
||||||
@ -32,13 +32,16 @@ class _RoutinesViewState extends State<RoutinesView> {
|
|||||||
}
|
}
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: SideSpacesView(
|
const Expanded(
|
||||||
onSelectAction: (String communityId, String spaceId) {
|
child:
|
||||||
context.read<RoutineBloc>()
|
// SideSpacesView(
|
||||||
..add(LoadScenes(spaceId, communityId))
|
// onSelectAction: (String communityId, String spaceId) {
|
||||||
..add(LoadAutomation(spaceId));
|
// // context.read<RoutineBloc>()
|
||||||
},
|
// // ..add(LoadScenes(spaceId, communityId))
|
||||||
)),
|
// // ..add(LoadAutomation(spaceId));
|
||||||
|
// },
|
||||||
|
// )
|
||||||
|
SideTreeView()),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -8,21 +8,26 @@ import 'package:syncrow_web/services/space_mana_api.dart';
|
|||||||
class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||||
String selectedCommunityId = '';
|
String selectedCommunityId = '';
|
||||||
String selectedSpaceId = '';
|
String selectedSpaceId = '';
|
||||||
|
|
||||||
SpaceTreeBloc() : super(const SpaceTreeState()) {
|
SpaceTreeBloc() : super(const SpaceTreeState()) {
|
||||||
on<InitialEvent>(_fetchSpaces);
|
on<InitialEvent>(_fetchSpaces);
|
||||||
on<OnSelectSpaceEvent>(_onSelectSpace);
|
on<OnCommunityExpanded>(_onCommunityExpanded);
|
||||||
|
on<OnSpaceExpanded>(_onSpaceExpanded);
|
||||||
|
on<OnCommunitySelected>(_onCommunitySelected);
|
||||||
|
on<OnSpaceSelected>(_onSpaceSelected);
|
||||||
|
on<SearchQueryEvent>(_onSearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
_fetchSpaces(InitialEvent event, Emitter<SpaceTreeState> emit) async {
|
_fetchSpaces(InitialEvent event, Emitter<SpaceTreeState> emit) async {
|
||||||
emit(SpaceTreeLoadingState());
|
emit(SpaceTreeLoadingState());
|
||||||
try {
|
try {
|
||||||
// _onloadProducts();
|
|
||||||
List<CommunityModel> communities = await CommunitySpaceManagementApi().fetchCommunities();
|
List<CommunityModel> communities = await CommunitySpaceManagementApi().fetchCommunities();
|
||||||
|
|
||||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
List<CommunityModel> updatedCommunities = await Future.wait(
|
||||||
communities.map((community) async {
|
communities.map((community) async {
|
||||||
List<SpaceModel> spaces =
|
List<SpaceModel> spaces =
|
||||||
await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid);
|
await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid);
|
||||||
|
|
||||||
return CommunityModel(
|
return CommunityModel(
|
||||||
uuid: community.uuid,
|
uuid: community.uuid,
|
||||||
createdAt: community.createdAt,
|
createdAt: community.createdAt,
|
||||||
@ -35,35 +40,170 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
}).toList(),
|
}).toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (updatedCommunities.isNotEmpty &&
|
|
||||||
state.selectedSpace.isEmpty &&
|
|
||||||
state.selectedCommunity.isEmpty) {
|
|
||||||
selectedCommunityId = updatedCommunities[0].uuid;
|
|
||||||
} else {
|
|
||||||
selectedCommunityId = state.selectedCommunity;
|
|
||||||
selectedSpaceId = state.selectedSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
communitiesList: updatedCommunities,
|
communitiesList: updatedCommunities, expandedCommunity: [], expandedSpaces: []));
|
||||||
selectedCommunity: selectedCommunityId,
|
|
||||||
selectedSpace: selectedSpaceId));
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSelectSpace(OnSelectSpaceEvent event, Emitter<SpaceTreeState> emit) async {
|
_onCommunityExpanded(OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
|
||||||
try {
|
try {
|
||||||
selectedCommunityId = event.communityId;
|
List<String> updatedExpandedCommunityList = List.from(state.expandedCommunities);
|
||||||
selectedSpaceId = event.spaceId;
|
|
||||||
|
if (updatedExpandedCommunityList.contains(event.communityId)) {
|
||||||
|
updatedExpandedCommunityList.remove(event.communityId);
|
||||||
|
} else {
|
||||||
|
updatedExpandedCommunityList.add(event.communityId);
|
||||||
|
}
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
communitiesList: state.spacesList,
|
expandedCommunity: updatedExpandedCommunityList,
|
||||||
selectedCommunity: event.communityId,
|
));
|
||||||
selectedSpace: event.spaceId));
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onSpaceExpanded(OnSpaceExpanded event, Emitter<SpaceTreeState> emit) async {
|
||||||
|
try {
|
||||||
|
List<String> 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<SpaceTreeState> emit) async {
|
||||||
|
try {
|
||||||
|
List<String> updatedSelectedCommunities = List.from(state.selectedCommunities);
|
||||||
|
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces);
|
||||||
|
List<String> updatedSoldChecks = List.from(state.soldCheck);
|
||||||
|
|
||||||
|
List<String> 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<SpaceTreeState> emit) async {
|
||||||
|
try {
|
||||||
|
List<String> updatedSelectedCommunities = List.from(state.selectedCommunities);
|
||||||
|
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces);
|
||||||
|
List<String> updatedSoldChecks = List.from(state.soldCheck);
|
||||||
|
|
||||||
|
List<String> childrenIds = _getAllChildIds(event.children);
|
||||||
|
|
||||||
|
// List<String> 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<SpaceTreeState> emit) async {
|
||||||
|
try {
|
||||||
|
List<CommunityModel> communities = List.from(state.communityList);
|
||||||
|
List<CommunityModel> 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<String> _getAllChildIds(List<SpaceModel> spaces) {
|
||||||
|
List<String> 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<String> ids = _getAllChildIds(community.spaces);
|
||||||
|
for (var id in ids) {
|
||||||
|
result = state.selectedSpaces.contains(id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
|
|
||||||
class SpaceTreeEvent extends Equatable {
|
class SpaceTreeEvent extends Equatable {
|
||||||
const SpaceTreeEvent();
|
const SpaceTreeEvent();
|
||||||
@ -9,16 +10,6 @@ class SpaceTreeEvent extends Equatable {
|
|||||||
|
|
||||||
class InitialEvent extends SpaceTreeEvent {}
|
class InitialEvent extends SpaceTreeEvent {}
|
||||||
|
|
||||||
class OnSelectSpaceEvent extends SpaceTreeEvent {
|
|
||||||
final String communityId;
|
|
||||||
final String spaceId;
|
|
||||||
|
|
||||||
const OnSelectSpaceEvent(this.communityId, this.spaceId);
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [communityId, spaceId];
|
|
||||||
}
|
|
||||||
|
|
||||||
class SearchForSpace extends SpaceTreeEvent {
|
class SearchForSpace extends SpaceTreeEvent {
|
||||||
final String searchQuery;
|
final String searchQuery;
|
||||||
|
|
||||||
@ -27,3 +18,52 @@ class SearchForSpace extends SpaceTreeEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [searchQuery];
|
List<Object> get props => [searchQuery];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class OnCommunityExpanded extends SpaceTreeEvent {
|
||||||
|
final String communityId;
|
||||||
|
|
||||||
|
const OnCommunityExpanded(this.communityId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [communityId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class OnCommunitySelected extends SpaceTreeEvent {
|
||||||
|
final String communityId;
|
||||||
|
final List<SpaceModel> children;
|
||||||
|
|
||||||
|
const OnCommunitySelected(this.communityId, this.children);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [communityId, children];
|
||||||
|
}
|
||||||
|
|
||||||
|
class OnSpaceExpanded extends SpaceTreeEvent {
|
||||||
|
final String communityId;
|
||||||
|
final String spaceId;
|
||||||
|
|
||||||
|
const OnSpaceExpanded(this.communityId, this.spaceId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [communityId, spaceId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class OnSpaceSelected extends SpaceTreeEvent {
|
||||||
|
final String communityId;
|
||||||
|
final String spaceId;
|
||||||
|
final List<SpaceModel> children;
|
||||||
|
|
||||||
|
const OnSpaceSelected(this.communityId, this.spaceId, this.children);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [communityId, spaceId, children];
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchQueryEvent extends SpaceTreeEvent {
|
||||||
|
final String searchQuery;
|
||||||
|
|
||||||
|
const SearchQueryEvent(this.searchQuery);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [searchQuery];
|
||||||
|
}
|
||||||
|
@ -2,23 +2,56 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
|
|
||||||
class SpaceTreeState extends Equatable {
|
class SpaceTreeState extends Equatable {
|
||||||
final List<CommunityModel> spacesList;
|
final List<CommunityModel> communityList;
|
||||||
final String selectedSpace;
|
final List<CommunityModel> filteredCommunity;
|
||||||
final String selectedCommunity;
|
final List<String> expandedCommunities;
|
||||||
|
final List<String> expandedSpaces;
|
||||||
|
final List<String> selectedCommunities;
|
||||||
|
final List<String> selectedSpaces;
|
||||||
|
final List<String> soldCheck;
|
||||||
|
final bool isSearching;
|
||||||
|
|
||||||
const SpaceTreeState(
|
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(
|
SpaceTreeState copyWith(
|
||||||
{List<CommunityModel>? communitiesList, String? selectedSpace, String? selectedCommunity}) {
|
{List<CommunityModel>? communitiesList,
|
||||||
|
List<CommunityModel>? filteredCommunity,
|
||||||
|
List<String>? expandedSpaces,
|
||||||
|
List<String>? expandedCommunity,
|
||||||
|
List<String>? selectedCommunities,
|
||||||
|
List<String>? selectedSpaces,
|
||||||
|
List<String>? soldCheck,
|
||||||
|
bool? isSearching}) {
|
||||||
return SpaceTreeState(
|
return SpaceTreeState(
|
||||||
spacesList: communitiesList ?? this.spacesList,
|
communityList: communitiesList ?? this.communityList,
|
||||||
selectedSpace: selectedSpace ?? this.selectedSpace,
|
filteredCommunity: filteredCommunity ?? this.filteredCommunity,
|
||||||
selectedCommunity: selectedCommunity ?? this.selectedCommunity);
|
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
|
@override
|
||||||
List<Object?> get props => [spacesList, selectedSpace, selectedCommunity];
|
List<Object?> get props => [
|
||||||
|
communityList,
|
||||||
|
filteredCommunity,
|
||||||
|
expandedSpaces,
|
||||||
|
expandedCommunities,
|
||||||
|
selectedCommunities,
|
||||||
|
selectedSpaces,
|
||||||
|
soldCheck,
|
||||||
|
isSearching
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpaceTreeLoadingState extends SpaceTreeState {}
|
class SpaceTreeLoadingState extends SpaceTreeState {}
|
||||||
@ -26,6 +59,7 @@ class SpaceTreeLoadingState extends SpaceTreeState {}
|
|||||||
class SpaceTreeErrorState extends SpaceTreeState {
|
class SpaceTreeErrorState extends SpaceTreeState {
|
||||||
final String message;
|
final String message;
|
||||||
const SpaceTreeErrorState(this.message);
|
const SpaceTreeErrorState(this.message);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [message];
|
List<Object?> get props => [message];
|
||||||
}
|
}
|
||||||
|
@ -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<Widget>? 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 ?? [],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +1,26 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class CustomExpansionTileSpaceTree extends StatefulWidget {
|
class CustomExpansionTileSpaceTree extends StatelessWidget {
|
||||||
|
final String? spaceId;
|
||||||
final String title;
|
final String title;
|
||||||
final List<Widget>? children;
|
final List<Widget>? children;
|
||||||
final bool initiallyExpanded;
|
final bool isSelected;
|
||||||
final bool isSelected; // Add this to track selection
|
final bool isSoldCheck;
|
||||||
final bool? isExpanded; // External control over expansion
|
final bool isExpanded;
|
||||||
final ValueChanged<bool>? onExpansionChanged; // Notify when expansion changes
|
final Function? onExpansionChanged;
|
||||||
final VoidCallback? onItemSelected; // Callback for selecting the item
|
final Function? onItemSelected;
|
||||||
|
|
||||||
CustomExpansionTileSpaceTree({
|
const CustomExpansionTileSpaceTree(
|
||||||
required this.title,
|
{super.key,
|
||||||
this.children,
|
this.spaceId,
|
||||||
this.initiallyExpanded = false,
|
required this.title,
|
||||||
this.isExpanded, // Allow external control over expansion
|
this.children,
|
||||||
this.onExpansionChanged, // Notify when expansion changes
|
this.isExpanded = false,
|
||||||
this.onItemSelected, // Trigger item selection when name is tapped
|
this.onExpansionChanged,
|
||||||
required this.isSelected, // Add this to initialize selection state
|
this.onItemSelected,
|
||||||
});
|
required this.isSelected,
|
||||||
|
this.isSoldCheck = false});
|
||||||
@override
|
|
||||||
CustomExpansionTileState createState() => CustomExpansionTileState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class CustomExpansionTileState extends State<CustomExpansionTileSpaceTree> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -56,14 +28,14 @@ class CustomExpansionTileState extends State<CustomExpansionTileSpaceTree> {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
// Checkbox with independent state management
|
|
||||||
Checkbox(
|
Checkbox(
|
||||||
value: widget.isSelected,
|
value: isSoldCheck ? null : isSelected,
|
||||||
onChanged: (bool? value) {
|
onChanged: (bool? value) {
|
||||||
if (widget.onItemSelected != null) {
|
if (onItemSelected != null) {
|
||||||
widget.onItemSelected!();
|
onItemSelected!();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
tristate: true,
|
||||||
side: WidgetStateBorderSide.resolveWith((states) {
|
side: WidgetStateBorderSide.resolveWith((states) {
|
||||||
return const BorderSide(color: ColorsManager.grayBorder);
|
return const BorderSide(color: ColorsManager.grayBorder);
|
||||||
}),
|
}),
|
||||||
@ -76,52 +48,52 @@ class CustomExpansionTileState extends State<CustomExpansionTileSpaceTree> {
|
|||||||
}),
|
}),
|
||||||
checkColor: ColorsManager.whiteColors,
|
checkColor: ColorsManager.whiteColors,
|
||||||
),
|
),
|
||||||
// Expand/collapse icon, now wrapped in a GestureDetector for specific onTap
|
if (children != null && children!.isNotEmpty)
|
||||||
if (widget.children != null && widget.children!.isNotEmpty)
|
InkWell(
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
if (onExpansionChanged != null) {
|
||||||
_isExpanded = !_isExpanded;
|
onExpansionChanged!();
|
||||||
widget.onExpansionChanged?.call(_isExpanded);
|
}
|
||||||
});
|
|
||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
_isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right,
|
isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right,
|
||||||
color: ColorsManager.lightGrayColor,
|
color: ColorsManager.lightGrayColor,
|
||||||
size: 16.0, // Adjusted size for better alignment
|
size: 16.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// The title text, wrapped in GestureDetector to handle selection
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.onItemSelected != null) {
|
if (onItemSelected != null) {
|
||||||
widget.onItemSelected!();
|
onItemSelected!();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
_capitalizeFirstLetter(widget.title),
|
_capitalizeFirstLetter(title),
|
||||||
style: TextStyle(
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
color: widget.isSelected
|
color: isSelected
|
||||||
? ColorsManager.blackColor // Change color to black when selected
|
? ColorsManager.blackColor // Change color to black when selected
|
||||||
: ColorsManager.lightGrayColor, // Gray when not selected
|
: ColorsManager.lightGrayColor, // Gray when not selected
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// The expanded section (children) that shows when the tile is expanded
|
if (isExpanded && children != null && children!.isNotEmpty)
|
||||||
if (_isExpanded && widget.children != null && widget.children!.isNotEmpty)
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 48.0), // Indented children
|
padding: const EdgeInsets.only(left: 48.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: children ?? [],
|
||||||
children: widget.children!,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _capitalizeFirstLetter(String text) {
|
||||||
|
if (text.isEmpty) return text;
|
||||||
|
return text[0].toUpperCase() + text.substring(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<SpaceTreeBloc, SpaceTreeState>(
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
120
lib/pages/space_tree/view/side_tree_view.dart
Normal file
120
lib/pages/space_tree/view/side_tree_view.dart
Normal file
@ -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<SpaceTreeBloc, SpaceTreeState>(builder: (context, state) {
|
||||||
|
List<CommunityModel> 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<SpaceTreeBloc>().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<SpaceTreeBloc>()
|
||||||
|
.add(OnCommunityExpanded(community.uuid));
|
||||||
|
},
|
||||||
|
isExpanded:
|
||||||
|
state.expandedCommunities.contains(community.uuid),
|
||||||
|
onItemSelected: () {
|
||||||
|
context.read<SpaceTreeBloc>().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<SpaceTreeBloc>().add(OnSpaceSelected(
|
||||||
|
community.uuid, space.uuid ?? '', space.children));
|
||||||
|
},
|
||||||
|
onExpansionChanged: () {
|
||||||
|
context.read<SpaceTreeBloc>().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<Widget> _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<SpaceTreeBloc>()
|
||||||
|
.add(OnSpaceSelected(communityId, child.uuid ?? '', child.children));
|
||||||
|
},
|
||||||
|
onExpansionChanged: () {
|
||||||
|
context.read<SpaceTreeBloc>().add(OnSpaceExpanded(communityId, child.uuid ?? ''));
|
||||||
|
},
|
||||||
|
children: _buildNestedSpaces(context, state, child, communityId),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
}
|
@ -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<bool> onExpansionChanged;
|
|
||||||
final List<Widget>? 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<SpaceTileSpaceTree> {
|
|
||||||
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 ?? [],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<CommunityModel> 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<SpaceTreeView> createState() => _SpaceTreeViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SpaceTreeViewState extends State<SpaceTreeView> {
|
|
||||||
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<CommunityModel> _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<SpaceManagementBloc>().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<SpaceTreeBloc>().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<SpaceTreeBloc>().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) {}
|
|
||||||
}
|
|
@ -73,7 +73,7 @@ class SceneApi {
|
|||||||
{showInDevice = false}) async {
|
{showInDevice = false}) async {
|
||||||
try {
|
try {
|
||||||
final response = await _httpService.get(
|
final response = await _httpService.get(
|
||||||
path: ApiEndpoints.getScenes
|
path: ApiEndpoints.getUnitScenes
|
||||||
.replaceAll('{spaceUuid}', spaceId)
|
.replaceAll('{spaceUuid}', spaceId)
|
||||||
.replaceAll('{communityUuid}', communityId)
|
.replaceAll('{communityUuid}', communityId)
|
||||||
.replaceAll('{projectId}', TempConst.projectId),
|
.replaceAll('{projectId}', TempConst.projectId),
|
||||||
|
Reference in New Issue
Block a user