mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-14 17:25:50 +00:00
Compare commits
4 Commits
SP-1677-fe
...
SP-1669-fe
Author | SHA1 | Date | |
---|---|---|---|
d14cc785a8 | |||
379ecec789 | |||
e6957d566d | |||
71cf0a636e |
@ -79,7 +79,6 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDeviceInfoSection() {
|
Widget _buildDeviceInfoSection() {
|
||||||
final isOnlineDevice = device.online != null && device.online!;
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 50),
|
padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 50),
|
||||||
child: Table(
|
child: Table(
|
||||||
@ -108,7 +107,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
'Installation Date and Time:',
|
'Installation Date and Time:',
|
||||||
formatDateTime(
|
formatDateTime(
|
||||||
DateTime.fromMillisecondsSinceEpoch(
|
DateTime.fromMillisecondsSinceEpoch(
|
||||||
(device.createTime ?? 0) * 1000,
|
((device.createTime ?? 0) * 1000),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -127,16 +126,12 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
),
|
),
|
||||||
TableRow(
|
TableRow(
|
||||||
children: [
|
children: [
|
||||||
_buildInfoRow(
|
_buildInfoRow('Status:', 'Online', statusColor: Colors.green),
|
||||||
'Status:',
|
|
||||||
isOnlineDevice ? 'Online' : 'offline',
|
|
||||||
statusColor: isOnlineDevice ? Colors.green : Colors.red,
|
|
||||||
),
|
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
'Last Offline Date and Time:',
|
'Last Offline Date and Time:',
|
||||||
formatDateTime(
|
formatDateTime(
|
||||||
DateTime.fromMillisecondsSinceEpoch(
|
DateTime.fromMillisecondsSinceEpoch(
|
||||||
(device.updateTime ?? 0) * 1000,
|
((device.updateTime ?? 0) * 1000),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||||
@ -12,8 +14,11 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
|||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class EditUserDialog extends StatefulWidget {
|
class EditUserDialog extends StatefulWidget {
|
||||||
final String? userId;
|
final RolesUserModel? user;
|
||||||
const EditUserDialog({super.key, this.userId});
|
const EditUserDialog({
|
||||||
|
super.key,
|
||||||
|
this.user,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_EditUserDialogState createState() => _EditUserDialogState();
|
_EditUserDialogState createState() => _EditUserDialogState();
|
||||||
@ -28,10 +33,11 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
create: (BuildContext context) => UsersBloc()
|
create: (BuildContext context) => UsersBloc()
|
||||||
// ..add(const LoadCommunityAndSpacesEvent())
|
// ..add(const LoadCommunityAndSpacesEvent())
|
||||||
..add(const RoleEvent())
|
..add(const RoleEvent())
|
||||||
..add(GetUserByIdEvent(uuid: widget.userId)),
|
..add(GetUserByIdEvent(uuid: widget.user!.uuid)),
|
||||||
child: BlocConsumer<UsersBloc, UsersState>(listener: (context, state) {
|
child: BlocConsumer<UsersBloc, UsersState>(listener: (context, state) {
|
||||||
if (state is SpacesLoadedState) {
|
if (state is SpacesLoadedState) {
|
||||||
BlocProvider.of<UsersBloc>(context).add(GetUserByIdEvent(uuid: widget.userId));
|
BlocProvider.of<UsersBloc>(context)
|
||||||
|
.add(GetUserByIdEvent(uuid: widget.user!.uuid));
|
||||||
}
|
}
|
||||||
}, builder: (context, state) {
|
}, builder: (context, state) {
|
||||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||||
@ -39,7 +45,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
return Dialog(
|
return Dialog(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||||
width: 900,
|
width: 900,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -68,7 +75,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
children: [
|
children: [
|
||||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||||
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
_buildStep3Indicator(
|
||||||
|
3, "Role & Permissions", _blocRole),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -86,7 +94,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _getFormContent(widget.userId),
|
child: _getFormContent(widget.user!),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
],
|
],
|
||||||
@ -116,13 +124,14 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
if (currentStep < 3) {
|
if (currentStep < 3) {
|
||||||
currentStep++;
|
currentStep++;
|
||||||
if (currentStep == 2) {
|
if (currentStep == 2) {
|
||||||
_blocRole.add(CheckStepStatus(isEditUser: true));
|
_blocRole
|
||||||
|
.add(CheckStepStatus(isEditUser: true));
|
||||||
} else if (currentStep == 3) {
|
} else if (currentStep == 3) {
|
||||||
_blocRole.add(const CheckSpacesStepStatus());
|
_blocRole.add(const CheckSpacesStepStatus());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_blocRole
|
_blocRole.add(EditInviteUsers(
|
||||||
.add(EditInviteUsers(context: context, userId: widget.userId!));
|
context: context, userId: widget.user!.uuid));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -131,7 +140,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: (_blocRole.isCompleteSpaces == false ||
|
color: (_blocRole.isCompleteSpaces == false ||
|
||||||
_blocRole.isCompleteBasics == false ||
|
_blocRole.isCompleteBasics == false ||
|
||||||
_blocRole.isCompleteRolePermissions == false) &&
|
_blocRole.isCompleteRolePermissions ==
|
||||||
|
false) &&
|
||||||
currentStep == 3
|
currentStep == 3
|
||||||
? ColorsManager.grayColor
|
? ColorsManager.grayColor
|
||||||
: ColorsManager.secondaryColor),
|
: ColorsManager.secondaryColor),
|
||||||
@ -146,15 +156,15 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _getFormContent(userid) {
|
Widget _getFormContent(RolesUserModel user) {
|
||||||
switch (currentStep) {
|
switch (currentStep) {
|
||||||
case 1:
|
case 1:
|
||||||
return BasicsView(
|
return BasicsView(
|
||||||
userId: userid,
|
userId: user.uuid,
|
||||||
);
|
);
|
||||||
case 2:
|
case 2:
|
||||||
return SpacesAccessView(
|
return SpacesAccessView(
|
||||||
userId: userid,
|
userId: user.uuid,
|
||||||
);
|
);
|
||||||
case 3:
|
case 3:
|
||||||
return const RolesAndPermission();
|
return const RolesAndPermission();
|
||||||
@ -166,6 +176,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
int step3 = 0;
|
int step3 = 0;
|
||||||
|
|
||||||
Widget _buildStep1Indicator(int step, String label, UsersBloc bloc) {
|
Widget _buildStep1Indicator(int step, String label, UsersBloc bloc) {
|
||||||
|
final isCurrentStep = currentStep == step;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -189,7 +200,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
currentStep == step
|
isCurrentStep
|
||||||
? Assets.currentProcessIcon
|
? Assets.currentProcessIcon
|
||||||
: bloc.isCompleteBasics == false
|
: bloc.isCompleteBasics == false
|
||||||
? Assets.wrongProcessIcon
|
? Assets.wrongProcessIcon
|
||||||
@ -204,8 +215,11 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
color: isCurrentStep
|
||||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.greyColor,
|
||||||
|
fontWeight:
|
||||||
|
isCurrentStep ? FontWeight.bold : FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -229,6 +243,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStep2Indicator(int step, String label, UsersBloc bloc) {
|
Widget _buildStep2Indicator(int step, String label, UsersBloc bloc) {
|
||||||
|
final isCurrentStep = currentStep == step;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -248,7 +263,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
currentStep == step
|
isCurrentStep
|
||||||
? Assets.currentProcessIcon
|
? Assets.currentProcessIcon
|
||||||
: bloc.isCompleteSpaces == false
|
: bloc.isCompleteSpaces == false
|
||||||
? Assets.wrongProcessIcon
|
? Assets.wrongProcessIcon
|
||||||
@ -263,8 +278,11 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
color: isCurrentStep
|
||||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.greyColor,
|
||||||
|
fontWeight:
|
||||||
|
isCurrentStep ? FontWeight.bold : FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -288,6 +306,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStep3Indicator(int step, String label, UsersBloc bloc) {
|
Widget _buildStep3Indicator(int step, String label, UsersBloc bloc) {
|
||||||
|
final isCurrentStep = currentStep == step;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -306,7 +325,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
currentStep == step
|
isCurrentStep
|
||||||
? Assets.currentProcessIcon
|
? Assets.currentProcessIcon
|
||||||
: bloc.isCompleteRolePermissions == false
|
: bloc.isCompleteRolePermissions == false
|
||||||
? Assets.wrongProcessIcon
|
? Assets.wrongProcessIcon
|
||||||
@ -321,8 +340,11 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
color: isCurrentStep
|
||||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.greyColor,
|
||||||
|
fontWeight:
|
||||||
|
isCurrentStep ? FontWeight.bold : FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -19,6 +19,7 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
|||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class UsersPage extends StatelessWidget {
|
class UsersPage extends StatelessWidget {
|
||||||
UsersPage({super.key});
|
UsersPage({super.key});
|
||||||
|
|
||||||
@ -451,33 +452,31 @@ class UsersPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
user.isEnabled != false
|
if (user.isEnabled != false)
|
||||||
? actionButton(
|
actionButton(
|
||||||
isActive: true,
|
isActive: true,
|
||||||
title: "Edit",
|
title: "Edit",
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context
|
context
|
||||||
.read<SpaceTreeBloc>()
|
.read<SpaceTreeBloc>()
|
||||||
.add(ClearCachedData());
|
.add(ClearCachedData());
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return EditUserDialog(
|
return EditUserDialog(user: user);
|
||||||
userId: user.uuid);
|
|
||||||
},
|
|
||||||
).then((v) {
|
|
||||||
if (v != null) {
|
|
||||||
if (v != null) {
|
|
||||||
_blocRole.add(const GetUsers());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
)
|
).then((v) {
|
||||||
: actionButton(
|
if (v != null) {
|
||||||
title: "Edit",
|
_blocRole.add(const GetUsers());
|
||||||
),
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else
|
||||||
|
actionButton(
|
||||||
|
title: "Edit",
|
||||||
|
),
|
||||||
actionButton(
|
actionButton(
|
||||||
title: "Delete",
|
title: "Delete",
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
class SpaceConnectionModel {
|
|
||||||
final String from;
|
|
||||||
final String to;
|
|
||||||
|
|
||||||
const SpaceConnectionModel({required this.from, required this.to});
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_connection_model.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class SpacesConnectionsArrowPainter extends CustomPainter {
|
|
||||||
final List<SpaceConnectionModel> connections;
|
|
||||||
final Map<String, Offset> positions;
|
|
||||||
final double cardWidth = 150.0;
|
|
||||||
final double cardHeight = 90.0;
|
|
||||||
final String? selectedSpaceUuid;
|
|
||||||
|
|
||||||
SpacesConnectionsArrowPainter({
|
|
||||||
required this.connections,
|
|
||||||
required this.positions,
|
|
||||||
this.selectedSpaceUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
void paint(Canvas canvas, Size size) {
|
|
||||||
for (final connection in connections) {
|
|
||||||
final isSelected = connection.to == selectedSpaceUuid;
|
|
||||||
final paint = Paint()
|
|
||||||
..color = isSelected
|
|
||||||
? ColorsManager.primaryColor
|
|
||||||
: ColorsManager.blackColor.withValues(alpha: 0.5)
|
|
||||||
..strokeWidth = 2.0
|
|
||||||
..style = PaintingStyle.stroke;
|
|
||||||
|
|
||||||
final from = positions[connection.from];
|
|
||||||
final to = positions[connection.to];
|
|
||||||
|
|
||||||
if (from != null && to != null) {
|
|
||||||
final startPoint =
|
|
||||||
Offset(from.dx + cardWidth / 2, from.dy + cardHeight - 10);
|
|
||||||
final endPoint = Offset(to.dx + cardWidth / 2, to.dy);
|
|
||||||
|
|
||||||
final path = Path()..moveTo(startPoint.dx, startPoint.dy);
|
|
||||||
|
|
||||||
final controlPoint1 = Offset(startPoint.dx, startPoint.dy + 60);
|
|
||||||
final controlPoint2 = Offset(endPoint.dx, endPoint.dy - 60);
|
|
||||||
|
|
||||||
path.cubicTo(controlPoint1.dx, controlPoint1.dy, controlPoint2.dx,
|
|
||||||
controlPoint2.dy, endPoint.dx, endPoint.dy);
|
|
||||||
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
|
|
||||||
final circlePaint = Paint()
|
|
||||||
..color = isSelected
|
|
||||||
? ColorsManager.primaryColor
|
|
||||||
: ColorsManager.blackColor.withValues(alpha: 0.5)
|
|
||||||
..style = PaintingStyle.fill
|
|
||||||
..blendMode = BlendMode.srcIn;
|
|
||||||
canvas.drawCircle(endPoint, 4, circlePaint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_dialog.dart';
|
|
||||||
|
|
||||||
abstract final class SpaceManagementCommunityDialogHelper {
|
|
||||||
static void showCreateDialog(BuildContext context) {
|
|
||||||
showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => CreateCommunityDialog(
|
|
||||||
title: const SelectableText('Community Name'),
|
|
||||||
onCreateCommunity: (community) {
|
|
||||||
context.read<CommunitiesBloc>().add(
|
|
||||||
InsertCommunity(community),
|
|
||||||
);
|
|
||||||
context.read<CommunitiesTreeSelectionBloc>().add(
|
|
||||||
SelectCommunityEvent(community: community),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,236 +0,0 @@
|
|||||||
import 'package:flutter/material.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/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/modules/communities/domain/models/community_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
|
||||||
|
|
||||||
class CommunityStructureCanvas extends StatefulWidget {
|
|
||||||
const CommunityStructureCanvas({
|
|
||||||
required this.community,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final CommunityModel community;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CommunityStructureCanvas> createState() =>_CommunityStructureCanvasState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
final Map<String, Offset> _positions = {};
|
|
||||||
final double _cardWidth = 150.0;
|
|
||||||
final double _cardHeight = 90.0;
|
|
||||||
final double _horizontalSpacing = 150.0;
|
|
||||||
final double _verticalSpacing = 120.0;
|
|
||||||
String? _selectedSpaceUuid;
|
|
||||||
|
|
||||||
late TransformationController _transformationController;
|
|
||||||
late AnimationController _animationController;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_transformationController = TransformationController();
|
|
||||||
_animationController = AnimationController(
|
|
||||||
vsync: this,
|
|
||||||
duration: const Duration(milliseconds: 100),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_transformationController.dispose();
|
|
||||||
_animationController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _runAnimation(Matrix4 target) {
|
|
||||||
final animation = Matrix4Tween(
|
|
||||||
begin: _transformationController.value,
|
|
||||||
end: target,
|
|
||||||
).animate(_animationController);
|
|
||||||
|
|
||||||
void listener() {
|
|
||||||
_transformationController.value = animation.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
animation.addListener(listener);
|
|
||||||
_animationController.forward(from: 0).whenCompleteOrCancel(() {
|
|
||||||
animation.removeListener(listener);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onSpaceTapped(String spaceUuid) {
|
|
||||||
setState(() {
|
|
||||||
_selectedSpaceUuid = spaceUuid;
|
|
||||||
});
|
|
||||||
|
|
||||||
final position = _positions[spaceUuid];
|
|
||||||
if (position == null) return;
|
|
||||||
|
|
||||||
const scale = 2.0;
|
|
||||||
final viewSize = context.size;
|
|
||||||
if (viewSize == null) return;
|
|
||||||
|
|
||||||
final x = -position.dx * scale + (viewSize.width / 2) - (_cardWidth * scale / 2);
|
|
||||||
final y =
|
|
||||||
-position.dy * scale + (viewSize.height / 2) - (_cardHeight * scale / 2);
|
|
||||||
|
|
||||||
final matrix = Matrix4.identity()
|
|
||||||
..translate(x, y)
|
|
||||||
..scale(scale);
|
|
||||||
|
|
||||||
_runAnimation(matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _resetSelectionAndZoom() {
|
|
||||||
setState(() {
|
|
||||||
_selectedSpaceUuid = null;
|
|
||||||
});
|
|
||||||
_runAnimation(Matrix4.identity());
|
|
||||||
}
|
|
||||||
|
|
||||||
void _calculateLayout(
|
|
||||||
List<SpaceModel> spaces,
|
|
||||||
int depth,
|
|
||||||
Map<int, double> levelXOffset,
|
|
||||||
) {
|
|
||||||
for (final space in spaces) {
|
|
||||||
double childSubtreeWidth = 0;
|
|
||||||
if (space.children.isNotEmpty) {
|
|
||||||
_calculateLayout(space.children, depth + 1, levelXOffset);
|
|
||||||
final firstChildPos = _positions[space.children.first.uuid];
|
|
||||||
final lastChildPos = _positions[space.children.last.uuid];
|
|
||||||
if (firstChildPos != null && lastChildPos != null) {
|
|
||||||
childSubtreeWidth = (lastChildPos.dx + _cardWidth) - firstChildPos.dx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final currentX = levelXOffset.putIfAbsent(depth, () => 0.0);
|
|
||||||
double? x;
|
|
||||||
|
|
||||||
if (space.children.isNotEmpty) {
|
|
||||||
final firstChildPos = _positions[space.children.first.uuid]!;
|
|
||||||
x = firstChildPos.dx + (childSubtreeWidth - _cardWidth) / 2;
|
|
||||||
} else {
|
|
||||||
x = currentX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x < currentX) {
|
|
||||||
final shiftX = currentX - x;
|
|
||||||
_shiftSubtree(space, shiftX);
|
|
||||||
final keysToShift = levelXOffset.keys.where((d) => d > depth).toList();
|
|
||||||
for (final key in keysToShift) {
|
|
||||||
levelXOffset[key] = levelXOffset[key]! + shiftX;
|
|
||||||
}
|
|
||||||
x += shiftX;
|
|
||||||
}
|
|
||||||
|
|
||||||
final y = depth * (_verticalSpacing + _cardHeight);
|
|
||||||
_positions[space.uuid] = Offset(x, y);
|
|
||||||
levelXOffset[depth] = x + _cardWidth + _horizontalSpacing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _shiftSubtree(SpaceModel space, double shiftX) {
|
|
||||||
if (_positions.containsKey(space.uuid)) {
|
|
||||||
_positions[space.uuid] = _positions[space.uuid]!.translate(shiftX, 0);
|
|
||||||
}
|
|
||||||
for (final child in space.children) {
|
|
||||||
_shiftSubtree(child, shiftX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> _buildTreeWidgets() {
|
|
||||||
_positions.clear();
|
|
||||||
final community = widget.community;
|
|
||||||
|
|
||||||
_calculateLayout(community.spaces, 0, {});
|
|
||||||
|
|
||||||
final widgets = <Widget>[];
|
|
||||||
final connections = <SpaceConnectionModel>[];
|
|
||||||
_generateWidgets(community.spaces, widgets, connections);
|
|
||||||
|
|
||||||
return [
|
|
||||||
CustomPaint(
|
|
||||||
painter: SpacesConnectionsArrowPainter(
|
|
||||||
connections: connections,
|
|
||||||
positions: _positions,
|
|
||||||
selectedSpaceUuid: _selectedSpaceUuid,
|
|
||||||
),
|
|
||||||
child: Stack(alignment: AlignmentDirectional.center, children: widgets),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
void _generateWidgets(
|
|
||||||
List<SpaceModel> spaces,
|
|
||||||
List<Widget> widgets,
|
|
||||||
List<SpaceConnectionModel> connections,
|
|
||||||
) {
|
|
||||||
for (final space in spaces) {
|
|
||||||
final position = _positions[space.uuid];
|
|
||||||
if (position == null) continue;
|
|
||||||
|
|
||||||
widgets.add(
|
|
||||||
Positioned(
|
|
||||||
left: position.dx,
|
|
||||||
top: position.dy,
|
|
||||||
width: _cardWidth,
|
|
||||||
height: _cardHeight,
|
|
||||||
child: SpaceCardWidget(
|
|
||||||
index: spaces.indexOf(space),
|
|
||||||
onPositionChanged: (newPosition) {},
|
|
||||||
buildSpaceContainer: (index) {
|
|
||||||
return Opacity(
|
|
||||||
opacity: 1.0,
|
|
||||||
child: SpaceCell(
|
|
||||||
index: index,
|
|
||||||
onTap: () => _onSpaceTapped(space.uuid),
|
|
||||||
icon: space.icon,
|
|
||||||
name: space.spaceName,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
screenSize: MediaQuery.sizeOf(context),
|
|
||||||
position: position,
|
|
||||||
isHovered: false,
|
|
||||||
onHoverChanged: (int index, bool isHovered) {},
|
|
||||||
onButtonTap: (int index, Offset newPosition) {},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (final child in space.children) {
|
|
||||||
connections.add(SpaceConnectionModel(from: space.uuid, to: child.uuid));
|
|
||||||
}
|
|
||||||
_generateWidgets(space.children, widgets, connections);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final treeWidgets = _buildTreeWidgets();
|
|
||||||
return InteractiveViewer(
|
|
||||||
transformationController: _transformationController,
|
|
||||||
boundaryMargin: EdgeInsets.symmetric(
|
|
||||||
horizontal: MediaQuery.sizeOf(context).width * 0.3,
|
|
||||||
vertical: MediaQuery.sizeOf(context).height * 0.2,
|
|
||||||
),
|
|
||||||
minScale: 0.5,
|
|
||||||
maxScale: 3.0,
|
|
||||||
constrained: false,
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: _resetSelectionAndZoom,
|
|
||||||
child: SizedBox(
|
|
||||||
width: MediaQuery.sizeOf(context).width * 2,
|
|
||||||
height: MediaQuery.sizeOf(context).height * 2,
|
|
||||||
child: Stack(children: treeWidgets),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class CommunityTemplateCell extends StatelessWidget {
|
|
||||||
const CommunityTemplateCell({
|
|
||||||
super.key,
|
|
||||||
required this.onTap,
|
|
||||||
required this.title,
|
|
||||||
});
|
|
||||||
|
|
||||||
final void Function() onTap;
|
|
||||||
final Widget title;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: onTap,
|
|
||||||
child: Column(
|
|
||||||
spacing: 8,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: AspectRatio(
|
|
||||||
aspectRatio: 2.0,
|
|
||||||
child: Container(
|
|
||||||
decoration: ShapeDecoration(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
side: const BorderSide(
|
|
||||||
width: 4,
|
|
||||||
strokeAlign: BorderSide.strokeAlignOutside,
|
|
||||||
color: ColorsManager.borderColor,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(5),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
DefaultTextStyle(
|
|
||||||
style: context.textTheme.bodyLarge!.copyWith(
|
|
||||||
color: ColorsManager.blackColor,
|
|
||||||
),
|
|
||||||
child: title,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class CreateSpaceButton extends StatelessWidget {
|
|
||||||
const CreateSpaceButton({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {},
|
|
||||||
child: Container(
|
|
||||||
height: 60,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.grey.withValues(alpha: 0.5),
|
|
||||||
spreadRadius: 5,
|
|
||||||
blurRadius: 7,
|
|
||||||
offset: const Offset(0, 3),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: Container(
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: ColorsManager.boxColor,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: const Icon(
|
|
||||||
Icons.add,
|
|
||||||
color: Colors.blue,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class PlusButtonWidget extends StatelessWidget {
|
|
||||||
final int index;
|
|
||||||
final String direction;
|
|
||||||
final Offset offset;
|
|
||||||
final void Function(int index, Offset newPosition) onButtonTap;
|
|
||||||
|
|
||||||
const PlusButtonWidget({
|
|
||||||
super.key,
|
|
||||||
required this.index,
|
|
||||||
required this.direction,
|
|
||||||
required this.offset,
|
|
||||||
required this.onButtonTap,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
if (direction == 'down') {
|
|
||||||
onButtonTap(index, const Offset(0, 150));
|
|
||||||
} else {
|
|
||||||
onButtonTap(index, const Offset(150, 0));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: ColorsManager.spaceColor,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: const Icon(
|
|
||||||
Icons.add,
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/plus_button_widget.dart';
|
|
||||||
|
|
||||||
class SpaceCardWidget extends StatelessWidget {
|
|
||||||
final int index;
|
|
||||||
final Size screenSize;
|
|
||||||
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({
|
|
||||||
super.key,
|
|
||||||
required this.index,
|
|
||||||
required this.onPositionChanged,
|
|
||||||
required this.screenSize,
|
|
||||||
required this.position,
|
|
||||||
required this.isHovered,
|
|
||||||
required this.onHoverChanged,
|
|
||||||
required this.onButtonTap,
|
|
||||||
required this.buildSpaceContainer,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MouseRegion(
|
|
||||||
onEnter: (_) => onHoverChanged(index, true),
|
|
||||||
onExit: (_) => onHoverChanged(index, false),
|
|
||||||
child: SizedBox(
|
|
||||||
width: 150,
|
|
||||||
height: 90,
|
|
||||||
child: Stack(
|
|
||||||
clipBehavior: Clip.none,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: [
|
|
||||||
buildSpaceContainer(index),
|
|
||||||
|
|
||||||
if (isHovered)
|
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
child: PlusButtonWidget(
|
|
||||||
index: index,
|
|
||||||
direction: 'down',
|
|
||||||
offset: Offset.zero,
|
|
||||||
onButtonTap: onButtonTap,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (isHovered)
|
|
||||||
Positioned(
|
|
||||||
right: -15,
|
|
||||||
child: PlusButtonWidget(
|
|
||||||
index: index,
|
|
||||||
direction: 'right',
|
|
||||||
offset: Offset.zero,
|
|
||||||
onButtonTap: onButtonTap,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class SpaceCell extends StatelessWidget {
|
|
||||||
final int index;
|
|
||||||
final String icon;
|
|
||||||
final String name;
|
|
||||||
final VoidCallback? onDoubleTap;
|
|
||||||
final VoidCallback? onTap;
|
|
||||||
|
|
||||||
const SpaceCell({
|
|
||||||
super.key,
|
|
||||||
required this.index,
|
|
||||||
required this.icon,
|
|
||||||
required this.name,
|
|
||||||
this.onTap,
|
|
||||||
this.onDoubleTap,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
onDoubleTap: onDoubleTap,
|
|
||||||
onTap: onTap,
|
|
||||||
child: Container(
|
|
||||||
width: 150,
|
|
||||||
height: 70,
|
|
||||||
decoration: _containerDecoration(),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
_buildIconContainer(),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
name,
|
|
||||||
style: theme.textTheme.bodyLarge?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: ColorsManager.blackColor,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildIconContainer() {
|
|
||||||
return Container(
|
|
||||||
width: 40,
|
|
||||||
height: double.infinity,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: ColorsManager.spaceColor,
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(15),
|
|
||||||
bottomLeft: Radius.circular(15),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
icon,
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxDecoration _containerDecoration() {
|
|
||||||
return BoxDecoration(
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: ColorsManager.lightGrayColor.withValues(alpha: 0.5),
|
|
||||||
spreadRadius: 2,
|
|
||||||
blurRadius: 5,
|
|
||||||
offset: const Offset(0, 3),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,4 @@
|
|||||||
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/widgets/space_management_community_structure.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_management_templates_view.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/widgets/space_management_communities_tree.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/widgets/space_management_communities_tree.dart';
|
||||||
|
|
||||||
class SpaceManagementBody extends StatelessWidget {
|
class SpaceManagementBody extends StatelessWidget {
|
||||||
@ -10,21 +6,9 @@ class SpaceManagementBody extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return const Row(
|
||||||
children: [
|
children: [
|
||||||
const SpaceManagementCommunitiesTree(),
|
SpaceManagementCommunitiesTree(),
|
||||||
Expanded(
|
|
||||||
child: BlocBuilder<CommunitiesTreeSelectionBloc,
|
|
||||||
CommunitiesTreeSelectionState>(
|
|
||||||
buildWhen: (previous, current) =>
|
|
||||||
previous.selectedCommunity != current.selectedCommunity,
|
|
||||||
builder: (context, state) => Visibility(
|
|
||||||
visible: state.selectedCommunity == null,
|
|
||||||
replacement: const SpaceManagementCommunityStructure(),
|
|
||||||
child: const SpaceManagementTemplatesView(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_canvas.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/create_space_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
|
||||||
|
|
||||||
class SpaceManagementCommunityStructure extends StatelessWidget {
|
|
||||||
const SpaceManagementCommunityStructure({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final selectedCommunity =
|
|
||||||
context.watch<CommunitiesTreeSelectionBloc>().state.selectedCommunity!;
|
|
||||||
const spacer = Spacer(flex: 10);
|
|
||||||
return Visibility(
|
|
||||||
visible: selectedCommunity.spaces.isNotEmpty,
|
|
||||||
replacement: const Row(
|
|
||||||
children: [spacer, Expanded(child: CreateSpaceButton()), spacer]),
|
|
||||||
child: CommunityStructureCanvas(community: selectedCommunity),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/helpers/space_management_community_dialog_helper.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_template_cell.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class SpaceManagementTemplatesView extends StatelessWidget {
|
|
||||||
const SpaceManagementTemplatesView({super.key});
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Expanded(
|
|
||||||
child: ColoredBox(
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
child: GridView.builder(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 20),
|
|
||||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
|
||||||
maxCrossAxisExtent: 400,
|
|
||||||
mainAxisSpacing: 10,
|
|
||||||
crossAxisSpacing: 10,
|
|
||||||
childAspectRatio: 2.0,
|
|
||||||
),
|
|
||||||
itemCount: _gridItems(context).length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final model = _gridItems(context)[index];
|
|
||||||
return CommunityTemplateCell(
|
|
||||||
onTap: model.onTap,
|
|
||||||
title: model.title,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<_CommunityTemplateModel> _gridItems(BuildContext context) {
|
|
||||||
return [
|
|
||||||
_CommunityTemplateModel(
|
|
||||||
title: const Text('Blank'),
|
|
||||||
onTap: () => SpaceManagementCommunityDialogHelper.showCreateDialog(context),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CommunityTemplateModel {
|
|
||||||
final Widget title;
|
|
||||||
final void Function() onTap;
|
|
||||||
|
|
||||||
_CommunityTemplateModel({
|
|
||||||
required this.title,
|
|
||||||
required this.onTap,
|
|
||||||
});
|
|
||||||
}
|
|
@ -32,7 +32,7 @@ class CommunitiesTreeSelectionBloc
|
|||||||
) {
|
) {
|
||||||
emit(
|
emit(
|
||||||
CommunitiesTreeSelectionState(
|
CommunitiesTreeSelectionState(
|
||||||
selectedCommunity: event.community,
|
selectedCommunity: null,
|
||||||
selectedSpace: event.space,
|
selectedSpace: event.space,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -8,7 +8,7 @@ sealed class CommunitiesTreeSelectionEvent extends Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class SelectCommunityEvent extends CommunitiesTreeSelectionEvent {
|
final class SelectCommunityEvent extends CommunitiesTreeSelectionEvent {
|
||||||
final CommunityModel community;
|
final CommunityModel? community;
|
||||||
|
|
||||||
const SelectCommunityEvent({required this.community});
|
const SelectCommunityEvent({required this.community});
|
||||||
@override
|
@override
|
||||||
@ -16,10 +16,9 @@ final class SelectCommunityEvent extends CommunitiesTreeSelectionEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class SelectSpaceEvent extends CommunitiesTreeSelectionEvent {
|
final class SelectSpaceEvent extends CommunitiesTreeSelectionEvent {
|
||||||
final SpaceModel space;
|
final SpaceModel? space;
|
||||||
final CommunityModel community;
|
|
||||||
|
|
||||||
const SelectSpaceEvent({required this.space, required this.community});
|
const SelectSpaceEvent({required this.space});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [space];
|
List<Object?> get props => [space];
|
||||||
|
@ -30,7 +30,7 @@ class SpaceManagementCommunitiesTreeSpaceTile extends StatelessWidget {
|
|||||||
initiallyExpanded: spaceIsExpanded,
|
initiallyExpanded: spaceIsExpanded,
|
||||||
onExpansionChanged: (expanded) {},
|
onExpansionChanged: (expanded) {},
|
||||||
onItemSelected: () => context.read<CommunitiesTreeSelectionBloc>().add(
|
onItemSelected: () => context.read<CommunitiesTreeSelectionBloc>().add(
|
||||||
SelectSpaceEvent(community: community, space: space),
|
SelectSpaceEvent(space: space),
|
||||||
),
|
),
|
||||||
children: space.children
|
children: space.children
|
||||||
.map(
|
.map(
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/helpers/space_management_community_dialog_helper.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/widgets/space_management_sidebar_add_community_button.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/widgets/space_management_sidebar_add_community_button.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_dialog.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';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
@ -40,7 +41,7 @@ class SpaceManagementSidebarHeader extends StatelessWidget {
|
|||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
_clearSelection(context);
|
_clearSelection(context);
|
||||||
} else {
|
} else {
|
||||||
SpaceManagementCommunityDialogHelper.showCreateDialog(context);
|
_showCreateCommunityDialog(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,4 +50,19 @@ class SpaceManagementSidebarHeader extends StatelessWidget {
|
|||||||
const ClearCommunitiesTreeSelectionEvent(),
|
const ClearCommunitiesTreeSelectionEvent(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showCreateCommunityDialog(BuildContext context) => showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => CreateCommunityDialog(
|
||||||
|
title: const Text('Community Name'),
|
||||||
|
onCreateCommunity: (community) {
|
||||||
|
context.read<CommunitiesBloc>().add(
|
||||||
|
InsertCommunity(community),
|
||||||
|
);
|
||||||
|
context.read<CommunitiesTreeSelectionBloc>().add(
|
||||||
|
SelectCommunityEvent(community: community),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ class RemoteCreateCommunityService implements CreateCommunityService {
|
|||||||
return _defaultErrorMessage;
|
return _defaultErrorMessage;
|
||||||
}
|
}
|
||||||
final error = body['error'] as Map<String, dynamic>?;
|
final error = body['error'] as Map<String, dynamic>?;
|
||||||
final errorMessage = error?['message'] as String? ?? '';
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
return errorMessage;
|
return errorMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +41,11 @@ class CreateCommunityDialog extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
onCreateCommunity.call(community);
|
onCreateCommunity.call(community);
|
||||||
break;
|
break;
|
||||||
case CreateCommunityFailure():
|
case CreateCommunityFailure(:final message):
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(message)),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user