mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
navigates to selected space when changed on sidebar in space management canvas.
This commit is contained in:
@ -1,18 +1,22 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_connection_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_connection_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/painters/spaces_connections_arrow_painter.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/painters/spaces_connections_arrow_painter.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_card_widget.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_card_widget.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_cell.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_cell.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
|
|
||||||
class CommunityStructureCanvas extends StatefulWidget {
|
class CommunityStructureCanvas extends StatefulWidget {
|
||||||
const CommunityStructureCanvas({
|
const CommunityStructureCanvas({
|
||||||
required this.community,
|
required this.community,
|
||||||
|
required this.selectedSpace,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final CommunityModel community;
|
final CommunityModel community;
|
||||||
|
final SpaceModel? selectedSpace;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CommunityStructureCanvas> createState() => _CommunityStructureCanvasState();
|
State<CommunityStructureCanvas> createState() => _CommunityStructureCanvasState();
|
||||||
@ -25,19 +29,30 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
final double _cardHeight = 90.0;
|
final double _cardHeight = 90.0;
|
||||||
final double _horizontalSpacing = 150.0;
|
final double _horizontalSpacing = 150.0;
|
||||||
final double _verticalSpacing = 120.0;
|
final double _verticalSpacing = 120.0;
|
||||||
String? _selectedSpaceUuid;
|
|
||||||
|
|
||||||
late TransformationController _transformationController;
|
late TransformationController _transformationController;
|
||||||
late AnimationController _animationController;
|
late AnimationController _animationController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
|
||||||
_transformationController = TransformationController();
|
_transformationController = TransformationController();
|
||||||
_animationController = AnimationController(
|
_animationController = AnimationController(
|
||||||
vsync: this,
|
vsync: this,
|
||||||
duration: const Duration(milliseconds: 100),
|
duration: const Duration(milliseconds: 150),
|
||||||
);
|
);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant CommunityStructureCanvas oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (widget.selectedSpace?.uuid != oldWidget.selectedSpace?.uuid) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (mounted) {
|
||||||
|
_animateToSpace(widget.selectedSpace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -63,15 +78,16 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSpaceTapped(String spaceUuid) {
|
void _animateToSpace(SpaceModel? space) {
|
||||||
setState(() {
|
if (space == null) {
|
||||||
_selectedSpaceUuid = spaceUuid;
|
_runAnimation(Matrix4.identity());
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final position = _positions[spaceUuid];
|
final position = _positions[space.uuid];
|
||||||
if (position == null) return;
|
if (position == null) return;
|
||||||
|
|
||||||
const scale = 2.0;
|
const scale = 1.5;
|
||||||
final viewSize = context.size;
|
final viewSize = context.size;
|
||||||
if (viewSize == null) return;
|
if (viewSize == null) return;
|
||||||
|
|
||||||
@ -86,11 +102,19 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
_runAnimation(matrix);
|
_runAnimation(matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onSpaceTapped(SpaceModel? space) {
|
||||||
|
context.read<CommunitiesTreeSelectionBloc>().add(
|
||||||
|
SelectSpaceEvent(community: widget.community, space: space),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _resetSelectionAndZoom() {
|
void _resetSelectionAndZoom() {
|
||||||
setState(() {
|
context.read<CommunitiesTreeSelectionBloc>().add(
|
||||||
_selectedSpaceUuid = null;
|
SelectSpaceEvent(
|
||||||
});
|
community: widget.community,
|
||||||
_runAnimation(Matrix4.identity());
|
space: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _calculateLayout(
|
void _calculateLayout(
|
||||||
@ -159,7 +183,7 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
painter: SpacesConnectionsArrowPainter(
|
painter: SpacesConnectionsArrowPainter(
|
||||||
connections: connections,
|
connections: connections,
|
||||||
positions: _positions,
|
positions: _positions,
|
||||||
selectedSpaceUuid: _selectedSpaceUuid,
|
selectedSpaceUuid: widget.selectedSpace?.uuid,
|
||||||
),
|
),
|
||||||
child: Stack(alignment: AlignmentDirectional.center, children: widgets),
|
child: Stack(alignment: AlignmentDirectional.center, children: widgets),
|
||||||
),
|
),
|
||||||
@ -182,24 +206,24 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
width: _cardWidth,
|
width: _cardWidth,
|
||||||
height: _cardHeight,
|
height: _cardHeight,
|
||||||
child: SpaceCardWidget(
|
child: SpaceCardWidget(
|
||||||
index: spaces.indexOf(space),
|
buildSpaceContainer: () {
|
||||||
onPositionChanged: (newPosition) {},
|
|
||||||
buildSpaceContainer: (index) {
|
|
||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: 1.0,
|
opacity: widget.selectedSpace == null
|
||||||
|
? 1.0
|
||||||
|
: widget.selectedSpace?.uuid != space.uuid
|
||||||
|
? 0.5
|
||||||
|
: 1.0,
|
||||||
child: SpaceCell(
|
child: SpaceCell(
|
||||||
index: index,
|
onTap: () => _onSpaceTapped(space),
|
||||||
onTap: () => _onSpaceTapped(space.uuid),
|
|
||||||
icon: space.icon,
|
icon: space.icon,
|
||||||
name: space.spaceName,
|
name: space.spaceName,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
screenSize: MediaQuery.sizeOf(context),
|
onTap: () => showDialog<void>(
|
||||||
position: position,
|
context: context,
|
||||||
isHovered: false,
|
builder: (context) => const Text('123'),
|
||||||
onHoverChanged: (int index, bool isHovered) {},
|
),
|
||||||
onButtonTap: (int index, Offset newPosition) {},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -218,7 +242,7 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
transformationController: _transformationController,
|
transformationController: _transformationController,
|
||||||
boundaryMargin: EdgeInsets.symmetric(
|
boundaryMargin: EdgeInsets.symmetric(
|
||||||
horizontal: MediaQuery.sizeOf(context).width * 0.3,
|
horizontal: MediaQuery.sizeOf(context).width * 0.3,
|
||||||
vertical: MediaQuery.sizeOf(context).height * 0.2,
|
vertical: MediaQuery.sizeOf(context).height * 0.3,
|
||||||
),
|
),
|
||||||
minScale: 0.5,
|
minScale: 0.5,
|
||||||
maxScale: 3.0,
|
maxScale: 3.0,
|
||||||
@ -226,8 +250,8 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: _resetSelectionAndZoom,
|
onTap: _resetSelectionAndZoom,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: MediaQuery.sizeOf(context).width * 2,
|
width: MediaQuery.sizeOf(context).width * 5,
|
||||||
height: MediaQuery.sizeOf(context).height * 2,
|
height: MediaQuery.sizeOf(context).height * 5,
|
||||||
child: Stack(children: treeWidgets),
|
child: Stack(children: treeWidgets),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -2,15 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class PlusButtonWidget extends StatelessWidget {
|
class PlusButtonWidget extends StatelessWidget {
|
||||||
final int index;
|
|
||||||
final String direction;
|
|
||||||
final Offset offset;
|
final Offset offset;
|
||||||
final void Function(int index, Offset newPosition) onButtonTap;
|
final void Function() onButtonTap;
|
||||||
|
|
||||||
const PlusButtonWidget({
|
const PlusButtonWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.index,
|
|
||||||
required this.direction,
|
|
||||||
required this.offset,
|
required this.offset,
|
||||||
required this.onButtonTap,
|
required this.onButtonTap,
|
||||||
});
|
});
|
||||||
@ -18,13 +14,7 @@ class PlusButtonWidget extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: onButtonTap,
|
||||||
if (direction == 'down') {
|
|
||||||
onButtonTap(index, const Offset(0, 150));
|
|
||||||
} else {
|
|
||||||
onButtonTap(index, const Offset(150, 0));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
|
@ -1,60 +1,39 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/plus_button_widget.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/plus_button_widget.dart';
|
||||||
|
|
||||||
class SpaceCardWidget extends StatelessWidget {
|
class SpaceCardWidget extends StatefulWidget {
|
||||||
final int index;
|
final void Function() onTap;
|
||||||
final Size screenSize;
|
final Widget Function() buildSpaceContainer;
|
||||||
final Offset position;
|
|
||||||
final bool isHovered;
|
|
||||||
final void Function(int index, bool isHovered) onHoverChanged;
|
|
||||||
final void Function(int index, Offset newPosition) onButtonTap;
|
|
||||||
final Widget Function(int index) buildSpaceContainer;
|
|
||||||
final ValueChanged<Offset> onPositionChanged;
|
|
||||||
|
|
||||||
const SpaceCardWidget({
|
const SpaceCardWidget({
|
||||||
super.key,
|
required this.onTap,
|
||||||
required this.index,
|
|
||||||
required this.onPositionChanged,
|
|
||||||
required this.screenSize,
|
|
||||||
required this.position,
|
|
||||||
required this.isHovered,
|
|
||||||
required this.onHoverChanged,
|
|
||||||
required this.onButtonTap,
|
|
||||||
required this.buildSpaceContainer,
|
required this.buildSpaceContainer,
|
||||||
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SpaceCardWidget> createState() => _SpaceCardWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SpaceCardWidgetState extends State<SpaceCardWidget> {
|
||||||
|
bool isHovered = false;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MouseRegion(
|
return MouseRegion(
|
||||||
onEnter: (_) => onHoverChanged(index, true),
|
onEnter: (_) => setState(() => isHovered = true),
|
||||||
onExit: (_) => onHoverChanged(index, false),
|
onExit: (_) => setState(() => isHovered = false),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 150,
|
|
||||||
height: 90,
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
buildSpaceContainer(index),
|
widget.buildSpaceContainer(),
|
||||||
|
|
||||||
if (isHovered)
|
if (isHovered)
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
child: PlusButtonWidget(
|
child: PlusButtonWidget(
|
||||||
index: index,
|
|
||||||
direction: 'down',
|
|
||||||
offset: Offset.zero,
|
offset: Offset.zero,
|
||||||
onButtonTap: onButtonTap,
|
onButtonTap: widget.onTap,
|
||||||
),
|
|
||||||
),
|
|
||||||
if (isHovered)
|
|
||||||
Positioned(
|
|
||||||
right: -15,
|
|
||||||
child: PlusButtonWidget(
|
|
||||||
index: index,
|
|
||||||
direction: 'right',
|
|
||||||
offset: Offset.zero,
|
|
||||||
onButtonTap: onButtonTap,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,29 +1,23 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
class SpaceCell extends StatelessWidget {
|
class SpaceCell extends StatelessWidget {
|
||||||
final int index;
|
|
||||||
final String icon;
|
final String icon;
|
||||||
final String name;
|
final String name;
|
||||||
final VoidCallback? onDoubleTap;
|
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
const SpaceCell({
|
const SpaceCell({
|
||||||
super.key,
|
super.key,
|
||||||
required this.index,
|
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.name,
|
required this.name,
|
||||||
this.onTap,
|
required this.onTap,
|
||||||
this.onDoubleTap,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onDoubleTap: onDoubleTap,
|
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 150,
|
width: 150,
|
||||||
@ -36,7 +30,7 @@ class SpaceCell extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
name,
|
name,
|
||||||
style: theme.textTheme.bodyLarge?.copyWith(
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
),
|
),
|
||||||
@ -63,7 +57,10 @@ class SpaceCell extends StatelessWidget {
|
|||||||
child: Center(
|
child: Center(
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
icon,
|
icon,
|
||||||
color: ColorsManager.whiteColors,
|
colorFilter: const ColorFilter.mode(
|
||||||
|
ColorsManager.whiteColors,
|
||||||
|
BlendMode.srcIn,
|
||||||
|
),
|
||||||
width: 24,
|
width: 24,
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
|
@ -9,14 +9,18 @@ class SpaceManagementCommunityStructure extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final selectedCommunity =
|
final selectionBloc = context.watch<CommunitiesTreeSelectionBloc>().state;
|
||||||
context.watch<CommunitiesTreeSelectionBloc>().state.selectedCommunity!;
|
final selectedCommunity = selectionBloc.selectedCommunity;
|
||||||
|
final selectedSpace = selectionBloc.selectedSpace;
|
||||||
const spacer = Spacer(flex: 10);
|
const spacer = Spacer(flex: 10);
|
||||||
return Visibility(
|
return Visibility(
|
||||||
visible: selectedCommunity.spaces.isNotEmpty,
|
visible: selectedCommunity!.spaces.isNotEmpty,
|
||||||
replacement: const Row(
|
replacement: const Row(
|
||||||
children: [spacer, Expanded(child: CreateSpaceButton()), spacer]),
|
children: [spacer, Expanded(child: CreateSpaceButton()), spacer]),
|
||||||
child: CommunityStructureCanvas(community: selectedCommunity),
|
child: CommunityStructureCanvas(
|
||||||
|
community: selectedCommunity,
|
||||||
|
selectedSpace: selectedSpace,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ final class SelectCommunityEvent extends CommunitiesTreeSelectionEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class SelectSpaceEvent extends CommunitiesTreeSelectionEvent {
|
final class SelectSpaceEvent extends CommunitiesTreeSelectionEvent {
|
||||||
final SpaceModel space;
|
final SpaceModel? space;
|
||||||
final CommunityModel community;
|
final CommunityModel community;
|
||||||
|
|
||||||
const SelectSpaceEvent({required this.space, required this.community});
|
const SelectSpaceEvent({required this.space, required this.community});
|
||||||
|
Reference in New Issue
Block a user