Compare commits

..

10 Commits

Author SHA1 Message Date
acefe6b433 fixed repeated duplication 2025-04-29 10:13:11 +04:00
63bc7a56de - Refactor the code in _RoutinesViewState to improve readability and maintainability.
- Update the indentation and add padding to the child widgets in the Column.
- Add a bottom padding to the empty state text in _buildEmptyState.
2025-04-28 16:49:22 +03:00
7b3635deae Merge pull request #166 from SyncrowIOT/bugfix/clear-search
fixed community search caching
2025-04-28 16:27:38 +04:00
58755eafe1 Merge branch 'dev' of https://github.com/SyncrowIOT/web into bugfix/clear-search 2025-04-28 16:26:47 +04:00
ce225818fb fixed community search caching 2025-04-28 16:25:43 +04:00
8762a7aaa8 Merge pull request #165 from SyncrowIOT/bugfix/white-page-rendering 2025-04-28 15:22:37 +04:00
8dc833b2c3 fixed blank page rendering 2025-04-28 15:21:28 +04:00
13cef151aa Merge pull request #164 from SyncrowIOT/bugfix/space-model-with-tags 2025-04-28 14:37:26 +04:00
ab23be9828 fixed the issue in selecting space model and tag 2025-04-28 14:36:27 +04:00
687b68ab22 Merge pull request #163 from SyncrowIOT/fix/duplication-flatten
Fix/duplication-flatten
2025-04-28 13:00:17 +04:00
7 changed files with 128 additions and 105 deletions

View File

@ -30,8 +30,8 @@ class _RoutinesViewState extends State<RoutinesView> {
final spaceId = result['space']; final spaceId = result['space'];
final bloc = BlocProvider.of<CreateRoutineBloc>(context); final bloc = BlocProvider.of<CreateRoutineBloc>(context);
final routineBloc = context.read<RoutineBloc>(); final routineBloc = context.read<RoutineBloc>();
bloc.add( bloc.add(SaveCommunityIdAndSpaceIdEvent(
SaveCommunityIdAndSpaceIdEvent(communityID: communityId, spaceID: spaceId)); communityID: communityId, spaceID: spaceId));
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true)); routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true));
} }
@ -61,34 +61,38 @@ class _RoutinesViewState extends State<RoutinesView> {
width: context.screenWidth, width: context.screenWidth,
child: SingleChildScrollView( child: SingleChildScrollView(
padding: const EdgeInsetsDirectional.all(16), padding: const EdgeInsetsDirectional.all(16),
child: Column( child: Padding(
crossAxisAlignment: CrossAxisAlignment.start, padding: const EdgeInsets.only(left: 20),
mainAxisAlignment: MainAxisAlignment.start, child: Column(
spacing: 16, crossAxisAlignment: CrossAxisAlignment.start,
children: [ mainAxisAlignment: MainAxisAlignment.start,
Text( spacing: 16,
"Create New Routines", children: [
style: Theme.of(context).textTheme.titleLarge?.copyWith( Text(
color: ColorsManager.grayColor, "Create New Routines",
fontWeight: FontWeight.bold, style:
), Theme.of(context).textTheme.titleLarge?.copyWith(
), color: ColorsManager.grayColor,
RoutineViewCard( fontWeight: FontWeight.bold,
isLoading: false, ),
onChanged: (v) {}, ),
status: '', RoutineViewCard(
spaceId: '', isLoading: false,
automationId: '', onChanged: (v) {},
communityId: '', status: '',
sceneId: '', spaceId: '',
cardType: '', automationId: '',
spaceName: '', communityId: '',
onTap: () => _handleRoutineCreation(context), sceneId: '',
icon: Icons.add, cardType: '',
textString: '', spaceName: '',
), onTap: () => _handleRoutineCreation(context),
const FetchRoutineScenesAutomation(), icon: Icons.add,
], textString: '',
),
const FetchRoutineScenesAutomation(),
],
),
), ),
), ),
), ),

View File

@ -16,7 +16,8 @@ class FetchRoutineScenesAutomation extends StatelessWidget
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<RoutineBloc, RoutineState>( return BlocBuilder<RoutineBloc, RoutineState>(
builder: (context, state) { builder: (context, state) {
if (state.isLoading) return const Center(child: CircularProgressIndicator()); if (state.isLoading)
return const Center(child: CircularProgressIndicator());
return SingleChildScrollView( return SingleChildScrollView(
child: Padding( child: Padding(
@ -40,7 +41,8 @@ class FetchRoutineScenesAutomation extends StatelessWidget
const SizedBox(height: 3), const SizedBox(height: 3),
Visibility( Visibility(
visible: state.automations.isNotEmpty, visible: state.automations.isNotEmpty,
replacement: _buildEmptyState(context, "No automations found"), replacement:
_buildEmptyState(context, "No automations found"),
child: SizedBox( child: SizedBox(
height: 200, height: 200,
child: _buildAutomations(state), child: _buildAutomations(state),
@ -59,7 +61,8 @@ class FetchRoutineScenesAutomation extends StatelessWidget
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: state.automations.length, itemCount: state.automations.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final isLoading = state.automations.contains(state.automations[index].id); final isLoading =
state.automations.contains(state.automations[index].id);
return Column( return Column(
children: [ children: [
@ -179,10 +182,13 @@ class FetchRoutineScenesAutomation extends StatelessWidget
} }
Widget _buildEmptyState(BuildContext context, String title) { Widget _buildEmptyState(BuildContext context, String title) {
return Text( return Padding(
title, padding: const EdgeInsets.only(bottom: 100),
style: context.textTheme.bodyMedium?.copyWith( child: Text(
color: ColorsManager.grayColor, title,
style: context.textTheme.bodyMedium?.copyWith(
color: ColorsManager.grayColor,
),
), ),
); );
} }

View File

@ -466,6 +466,7 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
if (previousState is SpaceManagementLoaded) { if (previousState is SpaceManagementLoaded) {
await _updateLoadedState( await _updateLoadedState(
event.context,
previousState, previousState,
allSpaces, allSpaces,
event.communityUuid, event.communityUuid,
@ -482,6 +483,7 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
} }
Future<void> _updateLoadedState( Future<void> _updateLoadedState(
BuildContext context,
SpaceManagementLoaded previousState, SpaceManagementLoaded previousState,
List<SpaceModel> allSpaces, List<SpaceModel> allSpaces,
String communityUuid, String communityUuid,
@ -489,7 +491,10 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
) async { ) async {
var prevSpaceModels = await fetchSpaceModels(); var prevSpaceModels = await fetchSpaceModels();
await fetchTags(); await fetchTags();
final communities = List<CommunityModel>.from(previousState.communities); final spaceTreeState = context.read<SpaceTreeBloc>().state;
final communities = spaceTreeState.searchQuery.isNotEmpty
? spaceTreeState.filteredCommunity
: spaceTreeState.communityList;
for (var community in communities) { for (var community in communities) {
if (community.uuid == communityUuid) { if (community.uuid == communityUuid) {
@ -504,6 +509,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
spaceModels: prevSpaceModels, spaceModels: prevSpaceModels,
allTags: _cachedTags ?? [])); allTags: _cachedTags ?? []));
return; return;
} else {
print("Community not found");
} }
} }
} }
@ -634,11 +641,11 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
projectId: projectUuid); projectId: projectUuid);
} else { } else {
// Call create if the space does not have a UUID // Call create if the space does not have a UUID
final List<CreateTagBodyModel> tagBodyModels = space.tags != null List<CreateTagBodyModel> tagBodyModels = space.tags != null
? space.tags!.map((tag) => tag.toCreateTagBodyModel()).toList() ? space.tags!.map((tag) => tag.toCreateTagBodyModel()).toList()
: []; : [];
final createSubspaceBodyModels = space.subspaces?.map((subspace) { var createSubspaceBodyModels = space.subspaces?.map((subspace) {
final tagBodyModels = final tagBodyModels =
subspace.tags?.map((tag) => tag.toCreateTagBodyModel()).toList() ?? []; subspace.tags?.map((tag) => tag.toCreateTagBodyModel()).toList() ?? [];
return CreateSubspaceModel() return CreateSubspaceModel()
@ -647,6 +654,11 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
}).toList() ?? }).toList() ??
[]; [];
if (space.spaceModel?.uuid != null) {
tagBodyModels = [];
createSubspaceBodyModels = [];
}
final response = await _api.createSpace( final response = await _api.createSpace(
communityId: communityUuid, communityId: communityUuid,
name: space.name, name: space.name,

View File

@ -414,21 +414,20 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
return; return;
} }
result.add(space); result.add(space);
idToSpace[space.internalId] = space; idToSpace[space.internalId] = space;
for (var child in space.children) { for (var child in space.children) {
flatten(child); flatten(child);
} }
} }
for (var space in spaces) { for (var space in spaces) {
flatten(space); flatten(space);
} }
for (var space in result) { for (var space in result) {
if (space.parent != null) { if (space.parent != null) {
space.parent = idToSpace[space.parent!.internalId]; space.parent = idToSpace[space.parent!.internalId];
} }
} }
@ -704,62 +703,26 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
} }
void _duplicateSpace(SpaceModel space) { void _duplicateSpace(SpaceModel space) {
final double horizontalGap = 250.0;
final double verticalGap = 180.0;
final double nodeWidth = 200;
final double nodeHeight = 100;
final double breathingSpace = 300.0;
/// Helper to recursively duplicate a node and its children
SpaceModel duplicateRecursive(SpaceModel original, SpaceModel? duplicatedParent) {
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
final duplicated = SpaceModel(
name: duplicatedName,
icon: original.icon,
position: original.position,
isPrivate: original.isPrivate,
children: [],
status: SpaceStatus.newSpace,
parent: duplicatedParent,
spaceModel: original.spaceModel,
subspaces: original.subspaces,
tags: original.tags,
);
spaces.add(duplicated);
if (duplicatedParent != null) {
final newConnection = Connection(
startSpace: duplicatedParent,
endSpace: duplicated,
direction: "down",
);
connections.add(newConnection);
duplicated.incomingConnection = newConnection;
duplicatedParent.addOutgoingConnection(newConnection);
duplicatedParent.children.add(duplicated);
}
// Duplicate its children recursively
for (var child in original.children) {
duplicateRecursive(child, duplicated);
}
return duplicated;
}
/// Actual duplication process
setState(() { setState(() {
if (space.parent == null) { SpaceModel? parent = space.parent;
// Duplicating a ROOT node
duplicateRecursive(space, null); SpaceModel duplicated = _deepCloneSpaceTree(space, parent: parent);
connections = createConnections(spaces);
realignTree(); duplicated.position = Offset(space.position.dx + 300, space.position.dy + 100);
} else { List<SpaceModel> duplicatedSubtree = [];
final parent = space.parent!; void collectSubtree(SpaceModel node) {
duplicatedSubtree.add(node);
for (var child in node.children) {
collectSubtree(child);
}
}
collectSubtree(duplicated);
spaces.addAll(duplicatedSubtree);
if (parent != null) {
parent.children.add(duplicated);
final duplicated = duplicateRecursive(space, parent);
final newConnection = Connection( final newConnection = Connection(
startSpace: parent, startSpace: parent,
endSpace: duplicated, endSpace: duplicated,
@ -768,11 +731,44 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
connections.add(newConnection); connections.add(newConnection);
duplicated.incomingConnection = newConnection; duplicated.incomingConnection = newConnection;
parent.addOutgoingConnection(newConnection); parent.addOutgoingConnection(newConnection);
parent.children.add(duplicated);
connections = createConnections(spaces);
realignTree();
//_realignSubtree(space.parent!);
} }
realignTree();
connections = createConnections(spaces);
}); });
} }
SpaceModel _deepCloneSpaceTree(SpaceModel original, {SpaceModel? parent}) {
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
final newSpace = SpaceModel(
name: duplicatedName,
icon: original.icon,
position: original.position,
isPrivate: original.isPrivate,
children: [],
status: SpaceStatus.newSpace,
spaceModel: original.spaceModel,
subspaces: original.subspaces,
tags: original.tags,
parent: parent,
);
for (var child in original.children) {
final duplicatedChild = _deepCloneSpaceTree(child, parent: newSpace);
newSpace.children.add(duplicatedChild);
final newConnection = Connection(
startSpace: newSpace,
endSpace: duplicatedChild,
direction: "down",
);
connections.add(newConnection);
duplicatedChild.incomingConnection = newConnection;
newSpace.addOutgoingConnection(newConnection);
}
return newSpace;
}
} }

View File

@ -1,6 +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: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/bloc/space_tree_event.dart';
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
@ -45,7 +46,6 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_spaceModels = List.from(widget.spaceModels ?? []); _spaceModels = List.from(widget.spaceModels ?? []);
} }
@ -106,9 +106,8 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
children: [ children: [
SidebarWidget( SidebarWidget(
communities: widget.communities, communities: widget.communities,
selectedSpaceUuid: widget.selectedSpace?.uuid ?? selectedSpaceUuid:
widget.selectedCommunity?.uuid ?? widget.selectedSpace?.uuid ?? widget.selectedCommunity?.uuid ?? '',
'',
onCreateCommunity: (name, description) { onCreateCommunity: (name, description) {
context.read<SpaceManagementBloc>().add( context.read<SpaceManagementBloc>().add(
CreateCommunityEvent(name, description, context), CreateCommunityEvent(name, description, context),

View File

@ -50,6 +50,8 @@ class _SidebarWidgetState extends State<SidebarWidget> {
_scrollController = ScrollController(); _scrollController = ScrollController();
_scrollController.addListener(_onScroll); _scrollController.addListener(_onScroll);
_selectedId = widget.selectedSpaceUuid; _selectedId = widget.selectedSpaceUuid;
_searchQuery = '';
context.read<SpaceTreeBloc>().add(ClearCachedData());
} }
void _onScroll() { void _onScroll() {

View File

@ -1,5 +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: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/spaces_management/all_spaces/model/product_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_bloc.dart';
@ -27,6 +29,8 @@ class SpaceModelPage extends StatelessWidget {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (state is SpaceModelLoaded) { } else if (state is SpaceModelLoaded) {
final spaceModels = state.spaceModels; final spaceModels = state.spaceModels;
context.read<SpaceTreeBloc>().add(ClearCachedData());
final allTagValues = _getAllTagValues(spaceModels); final allTagValues = _getAllTagValues(spaceModels);
final allSpaceModelNames = _getAllSpaceModelName(spaceModels); final allSpaceModelNames = _getAllSpaceModelName(spaceModels);