mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-15 09:45:25 +00:00
Compare commits
7 Commits
SP-1708-FE
...
hot-fix-th
Author | SHA1 | Date | |
---|---|---|---|
b06e4bd2ba | |||
0a022d8a8d | |||
8f0eb88567 | |||
19739c6e4d | |||
9f86b8d638 | |||
037895844a | |||
e6fe9f35b0 |
@ -15,7 +15,8 @@ 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/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayout {
|
class AcDeviceBatchControlView extends StatelessWidget
|
||||||
|
with HelperResponsiveLayout {
|
||||||
const AcDeviceBatchControlView({super.key, required this.devicesIds});
|
const AcDeviceBatchControlView({super.key, required this.devicesIds});
|
||||||
|
|
||||||
final List<String> devicesIds;
|
final List<String> devicesIds;
|
||||||
@ -51,7 +52,7 @@ class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayo
|
|||||||
deviceId: devicesIds.first,
|
deviceId: devicesIds.first,
|
||||||
code: 'switch',
|
code: 'switch',
|
||||||
value: state.status.acSwitch,
|
value: state.status.acSwitch,
|
||||||
label: 'ThermoState',
|
label: 'Thermostat',
|
||||||
icon: Assets.ac,
|
icon: Assets.ac,
|
||||||
onChange: (value) {
|
onChange: (value) {
|
||||||
context.read<AcBloc>().add(AcBatchControlEvent(
|
context.read<AcBloc>().add(AcBatchControlEvent(
|
||||||
@ -100,8 +101,8 @@ class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayo
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'h',
|
'h',
|
||||||
style:
|
style: context.textTheme.bodySmall!
|
||||||
context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor),
|
.copyWith(color: ColorsManager.blackColor),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'30',
|
'30',
|
||||||
@ -148,7 +149,8 @@ class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayo
|
|||||||
callFactoryReset: () {
|
callFactoryReset: () {
|
||||||
context.read<AcBloc>().add(AcFactoryResetEvent(
|
context.read<AcBloc>().add(AcFactoryResetEvent(
|
||||||
deviceId: state.status.uuid,
|
deviceId: state.status.uuid,
|
||||||
factoryResetModel: FactoryResetModel(devicesUuid: devicesIds),
|
factoryResetModel:
|
||||||
|
FactoryResetModel(devicesUuid: devicesIds),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -68,6 +68,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(child: SpaceTreeView(
|
Expanded(child: SpaceTreeView(
|
||||||
onSelect: () {
|
onSelect: () {
|
||||||
|
context.read<DeviceManagementBloc>().add(ResetFilters());
|
||||||
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
|
@ -277,6 +277,32 @@ class SmartPowerDeviceControl extends StatelessWidget
|
|||||||
totalConsumption: 10000,
|
totalConsumption: 10000,
|
||||||
date: blocProvider.formattedDate,
|
date: blocProvider.formattedDate,
|
||||||
),
|
),
|
||||||
|
EnergyConsumptionPage(
|
||||||
|
formattedDate:
|
||||||
|
'${blocProvider.dateTime!.day}/${blocProvider.dateTime!.month}/${blocProvider.dateTime!.year} ${blocProvider.endChartDate}',
|
||||||
|
onTap: () {
|
||||||
|
blocProvider.add(SelectDateEvent(context: context));
|
||||||
|
},
|
||||||
|
widget: blocProvider.dateSwitcher(),
|
||||||
|
chartData: blocProvider.energyDataList.isNotEmpty
|
||||||
|
? blocProvider.energyDataList
|
||||||
|
: [
|
||||||
|
EnergyData('12:00 AM', 4.0),
|
||||||
|
EnergyData('01:00 AM', 6.5),
|
||||||
|
EnergyData('02:00 AM', 3.8),
|
||||||
|
EnergyData('03:00 AM', 3.2),
|
||||||
|
EnergyData('04:00 AM', 6.0),
|
||||||
|
EnergyData('05:00 AM', 3.4),
|
||||||
|
EnergyData('06:00 AM', 5.2),
|
||||||
|
EnergyData('07:00 AM', 3.5),
|
||||||
|
EnergyData('08:00 AM', 6.8),
|
||||||
|
EnergyData('09:00 AM', 5.6),
|
||||||
|
EnergyData('10:00 AM', 3.9),
|
||||||
|
EnergyData('11:00 AM', 4.0),
|
||||||
|
],
|
||||||
|
totalConsumption: 10000,
|
||||||
|
date: blocProvider.formattedDate,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -232,7 +232,6 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
selectedDays: List.filled(7, false),
|
selectedDays: List.filled(7, false),
|
||||||
functionOn: false,
|
functionOn: false,
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
countdownRemaining: Duration.zero,
|
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
emit(ScheduleLoaded(
|
emit(ScheduleLoaded(
|
||||||
|
@ -105,7 +105,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
color: const Color(0xFF0026A2),
|
color: const Color(0xFF0026A2),
|
||||||
),
|
),
|
||||||
HomeItemModel(
|
HomeItemModel(
|
||||||
title: 'Device Management',
|
title: 'Devices Management',
|
||||||
icon: Assets.devicesIcon,
|
icon: Assets.devicesIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
|
@ -7,8 +7,6 @@ import 'package:syncrow_web/pages/space_management_v2/modules/communities/data/s
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.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/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/space_details/data/services/remote_space_details_service.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
@ -28,11 +26,6 @@ class SpaceManagementPage extends StatelessWidget {
|
|||||||
)..add(const LoadCommunities(LoadCommunitiesParam())),
|
)..add(const LoadCommunities(LoadCommunitiesParam())),
|
||||||
),
|
),
|
||||||
BlocProvider(create: (context) => CommunitiesTreeSelectionBloc()),
|
BlocProvider(create: (context) => CommunitiesTreeSelectionBloc()),
|
||||||
BlocProvider(
|
|
||||||
create: (context) => SpaceDetailsBloc(
|
|
||||||
RemoteSpaceDetailsService(httpService: HTTPService()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
child: WebScaffold(
|
child: WebScaffold(
|
||||||
appBarTitle: Text(
|
appBarTitle: Text(
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_header_action_buttons.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';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class CommunityStructureHeader extends StatelessWidget {
|
|
||||||
const CommunityStructureHeader({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: ColorsManager.shadowBlackColor,
|
|
||||||
blurRadius: 8,
|
|
||||||
offset: const Offset(0, 4),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: _buildCommunityInfo(context, theme, screenWidth),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showCreateCommunityDialog(BuildContext context) {
|
|
||||||
showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => CreateCommunityDialog(
|
|
||||||
title: const Text('Edit Community'),
|
|
||||||
onCreateCommunity: (community) {
|
|
||||||
// TODO(FarisArmoush): Implement
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildCommunityInfo(
|
|
||||||
BuildContext context, ThemeData theme, double screenWidth) {
|
|
||||||
final selectedCommunity =
|
|
||||||
context.watch<CommunitiesTreeSelectionBloc>().state.selectedCommunity;
|
|
||||||
final selectedSpace =
|
|
||||||
context.watch<CommunitiesTreeSelectionBloc>().state.selectedSpace;
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Community Structure',
|
|
||||||
style: theme.textTheme.headlineLarge
|
|
||||||
?.copyWith(color: ColorsManager.blackColor),
|
|
||||||
),
|
|
||||||
if (selectedCommunity != null)
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
child: SelectableText(
|
|
||||||
selectedCommunity.name,
|
|
||||||
style: theme.textTheme.bodyLarge
|
|
||||||
?.copyWith(color: ColorsManager.blackColor),
|
|
||||||
maxLines: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 2),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () => _showCreateCommunityDialog(context),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
Assets.iconEdit,
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
CommunityStructureHeaderActionButtons(
|
|
||||||
onDelete: (space) {},
|
|
||||||
onDuplicate: (space) {},
|
|
||||||
onEdit: (space) {
|
|
||||||
SpaceDetailsDialogHelper.showEdit(
|
|
||||||
context,
|
|
||||||
spaceModel: selectedSpace!,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
selectedSpace: selectedSpace,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_header_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class CommunityStructureHeaderActionButtons extends StatelessWidget {
|
|
||||||
const CommunityStructureHeaderActionButtons({
|
|
||||||
super.key,
|
|
||||||
required this.onDelete,
|
|
||||||
required this.selectedSpace,
|
|
||||||
required this.onDuplicate,
|
|
||||||
required this.onEdit,
|
|
||||||
});
|
|
||||||
|
|
||||||
final void Function(SpaceModel space) onDelete;
|
|
||||||
final void Function(SpaceModel space) onDuplicate;
|
|
||||||
final void Function(SpaceModel space) onEdit;
|
|
||||||
final SpaceModel? selectedSpace;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Wrap(
|
|
||||||
alignment: WrapAlignment.end,
|
|
||||||
spacing: 10,
|
|
||||||
children: [
|
|
||||||
if (selectedSpace != null) ...[
|
|
||||||
CommunityStructureHeaderButton(
|
|
||||||
label: 'Edit',
|
|
||||||
svgAsset: Assets.editSpace,
|
|
||||||
onPressed: () => onEdit(selectedSpace!),
|
|
||||||
),
|
|
||||||
CommunityStructureHeaderButton(
|
|
||||||
label: 'Duplicate',
|
|
||||||
svgAsset: Assets.duplicate,
|
|
||||||
onPressed: () => onDuplicate(selectedSpace!),
|
|
||||||
),
|
|
||||||
CommunityStructureHeaderButton(
|
|
||||||
label: 'Delete',
|
|
||||||
svgAsset: Assets.spaceDelete,
|
|
||||||
onPressed: () => onDelete(selectedSpace!),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class CommunityStructureHeaderButton extends StatelessWidget {
|
|
||||||
const CommunityStructureHeaderButton({
|
|
||||||
super.key,
|
|
||||||
required this.label,
|
|
||||||
required this.onPressed,
|
|
||||||
this.svgAsset,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String label;
|
|
||||||
final VoidCallback onPressed;
|
|
||||||
final String? svgAsset;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
const double buttonHeight = 40;
|
|
||||||
return ConstrainedBox(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxWidth: 130,
|
|
||||||
minHeight: buttonHeight,
|
|
||||||
),
|
|
||||||
child: DefaultButton(
|
|
||||||
onPressed: onPressed,
|
|
||||||
borderWidth: 2,
|
|
||||||
backgroundColor: ColorsManager.textFieldGreyColor,
|
|
||||||
foregroundColor: ColorsManager.blackColor,
|
|
||||||
borderRadius: 12.0,
|
|
||||||
padding: 2.0,
|
|
||||||
height: buttonHeight,
|
|
||||||
elevation: 0,
|
|
||||||
borderColor: ColorsManager.lightGrayColor,
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
if (svgAsset != null)
|
|
||||||
SvgPicture.asset(
|
|
||||||
svgAsset!,
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
label,
|
|
||||||
style: context.textTheme.bodySmall
|
|
||||||
?.copyWith(color: ColorsManager.blackColor, fontSize: 14),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
maxLines: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
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/widgets/community_structure_canvas.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/community_structure_header.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/create_space_button.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';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
|
|
||||||
@ -19,17 +18,9 @@ class SpaceManagementCommunityStructure extends StatelessWidget {
|
|||||||
replacement: const Row(
|
replacement: const Row(
|
||||||
children: [spacer, Expanded(child: CreateSpaceButton()), spacer],
|
children: [spacer, Expanded(child: CreateSpaceButton()), spacer],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: CommunityStructureCanvas(
|
||||||
mainAxisSize: MainAxisSize.min,
|
community: selectedCommunity,
|
||||||
children: [
|
selectedSpace: selectedSpace,
|
||||||
const CommunityStructureHeader(),
|
|
||||||
Expanded(
|
|
||||||
child: CommunityStructureCanvas(
|
|
||||||
community: selectedCommunity,
|
|
||||||
selectedSpace: selectedSpace,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,6 @@ class SpaceModel extends Equatable {
|
|||||||
required this.parent,
|
required this.parent,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SpaceModel.empty() => const SpaceModel(
|
|
||||||
uuid: '',
|
|
||||||
createdAt: null,
|
|
||||||
updatedAt: null,
|
|
||||||
spaceName: '',
|
|
||||||
icon: '',
|
|
||||||
children: [],
|
|
||||||
parent: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
factory SpaceModel.fromJson(Map<String, dynamic> json) {
|
factory SpaceModel.fromJson(Map<String, dynamic> json) {
|
||||||
return SpaceModel(
|
return SpaceModel(
|
||||||
uuid: json['uuid'] as String? ?? '',
|
uuid: json['uuid'] as String? ?? '',
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_spaces_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
||||||
import 'package:syncrow_web/services/api/api_exception.dart';
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
@ -16,15 +15,12 @@ class RemoteSpaceDetailsService implements SpaceDetailsService {
|
|||||||
static const _defaultErrorMessage = 'Failed to load space details';
|
static const _defaultErrorMessage = 'Failed to load space details';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<SpaceDetailsModel> getSpaceDetails(LoadSpaceDetailsParam param) async {
|
Future<SpaceDetailsModel> getSpaceDetails(LoadSpacesParam param) async {
|
||||||
try {
|
try {
|
||||||
final response = await _httpService.get(
|
final response = await _httpService.get(
|
||||||
path: await _makeEndpoint(param),
|
path: 'endpoint',
|
||||||
expectedResponseModel: (data) {
|
expectedResponseModel: (data) {
|
||||||
final response = data as Map<String, dynamic>;
|
return SpaceDetailsModel.fromJson(data as Map<String, dynamic>);
|
||||||
return SpaceDetailsModel.fromJson(
|
|
||||||
response['data'] as Map<String, dynamic>,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@ -41,13 +37,4 @@ class RemoteSpaceDetailsService implements SpaceDetailsService {
|
|||||||
throw APIException(formattedErrorMessage);
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _makeEndpoint(LoadSpaceDetailsParam param) async {
|
|
||||||
final projectUuid = await ProjectManager.getProjectUUID();
|
|
||||||
if (projectUuid == null || projectUuid.isEmpty) {
|
|
||||||
throw APIException('Project UUID is not set');
|
|
||||||
}
|
|
||||||
|
|
||||||
return '/projects/$projectUuid/communities/${param.communityUuid}/spaces/${param.spaceUuid}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/products/domain/models/product.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/products/domain/models/product.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class SpaceDetailsModel extends Equatable {
|
class SpaceDetailsModel extends Equatable {
|
||||||
final String uuid;
|
final String uuid;
|
||||||
@ -18,21 +17,14 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
required this.subspaces,
|
required this.subspaces,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SpaceDetailsModel.empty() => const SpaceDetailsModel(
|
|
||||||
uuid: '',
|
|
||||||
spaceName: '',
|
|
||||||
icon: Assets.villa,
|
|
||||||
productAllocations: [],
|
|
||||||
subspaces: [],
|
|
||||||
);
|
|
||||||
factory SpaceDetailsModel.fromJson(Map<String, dynamic> json) {
|
factory SpaceDetailsModel.fromJson(Map<String, dynamic> json) {
|
||||||
return SpaceDetailsModel(
|
return SpaceDetailsModel(
|
||||||
uuid: json['uuid'] as String,
|
uuid: json['uuid'] as String,
|
||||||
spaceName: json['spaceName'] as String,
|
spaceName: json['spaceName'] as String,
|
||||||
icon: json['icon'] as String,
|
icon: json['icon'] as String,
|
||||||
productAllocations: (json['productAllocations'] as List)
|
productAllocations: (json['productAllocations'] as List)
|
||||||
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
subspaces: (json['subspaces'] as List)
|
subspaces: (json['subspaces'] as List)
|
||||||
.map((e) => Subspace.fromJson(e as Map<String, dynamic>))
|
.map((e) => Subspace.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
@ -49,22 +41,6 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceDetailsModel copyWith({
|
|
||||||
String? uuid,
|
|
||||||
String? spaceName,
|
|
||||||
String? icon,
|
|
||||||
List<ProductAllocation>? productAllocations,
|
|
||||||
List<Subspace>? subspaces,
|
|
||||||
}) {
|
|
||||||
return SpaceDetailsModel(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
spaceName: spaceName ?? this.spaceName,
|
|
||||||
icon: icon ?? this.icon,
|
|
||||||
productAllocations: productAllocations ?? this.productAllocations,
|
|
||||||
subspaces: subspaces ?? this.subspaces,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uuid, spaceName, icon, productAllocations, subspaces];
|
List<Object?> get props => [uuid, spaceName, icon, productAllocations, subspaces];
|
||||||
}
|
}
|
||||||
@ -72,10 +48,12 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
class ProductAllocation extends Equatable {
|
class ProductAllocation extends Equatable {
|
||||||
final Product product;
|
final Product product;
|
||||||
final Tag tag;
|
final Tag tag;
|
||||||
|
final String? location;
|
||||||
|
|
||||||
const ProductAllocation({
|
const ProductAllocation({
|
||||||
required this.product,
|
required this.product,
|
||||||
required this.tag,
|
required this.tag,
|
||||||
|
this.location,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ProductAllocation.fromJson(Map<String, dynamic> json) {
|
factory ProductAllocation.fromJson(Map<String, dynamic> json) {
|
||||||
@ -92,16 +70,6 @@ class ProductAllocation extends Equatable {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ProductAllocation copyWith({
|
|
||||||
Product? product,
|
|
||||||
Tag? tag,
|
|
||||||
}) {
|
|
||||||
return ProductAllocation(
|
|
||||||
product: product ?? this.product,
|
|
||||||
tag: tag ?? this.tag,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [product, tag];
|
List<Object?> get props => [product, tag];
|
||||||
}
|
}
|
||||||
@ -120,7 +88,7 @@ class Subspace extends Equatable {
|
|||||||
factory Subspace.fromJson(Map<String, dynamic> json) {
|
factory Subspace.fromJson(Map<String, dynamic> json) {
|
||||||
return Subspace(
|
return Subspace(
|
||||||
uuid: json['uuid'] as String,
|
uuid: json['uuid'] as String,
|
||||||
name: json['subspaceName'] as String,
|
name: json['name'] as String,
|
||||||
productAllocations: (json['productAllocations'] as List)
|
productAllocations: (json['productAllocations'] as List)
|
||||||
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
@ -135,18 +103,6 @@ class Subspace extends Equatable {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Subspace copyWith({
|
|
||||||
String? uuid,
|
|
||||||
String? name,
|
|
||||||
List<ProductAllocation>? productAllocations,
|
|
||||||
}) {
|
|
||||||
return Subspace(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
name: name ?? this.name,
|
|
||||||
productAllocations: productAllocations ?? this.productAllocations,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uuid, name, productAllocations];
|
List<Object?> get props => [uuid, name, productAllocations];
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
class LoadSpaceDetailsParam {
|
|
||||||
const LoadSpaceDetailsParam({
|
|
||||||
required this.spaceUuid,
|
|
||||||
required this.communityUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String spaceUuid;
|
|
||||||
final String communityUuid;
|
|
||||||
}
|
|
@ -0,0 +1,3 @@
|
|||||||
|
class LoadSpacesParam {
|
||||||
|
const LoadSpacesParam();
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_spaces_param.dart';
|
||||||
|
|
||||||
abstract class SpaceDetailsService {
|
abstract class SpaceDetailsService {
|
||||||
Future<SpaceDetailsModel> getSpaceDetails(LoadSpaceDetailsParam param);
|
Future<SpaceDetailsModel> getSpaceDetails(LoadSpacesParam param);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_spaces_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
||||||
import 'package:syncrow_web/services/api/api_exception.dart';
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
@ -9,13 +9,12 @@ part 'space_details_event.dart';
|
|||||||
part 'space_details_state.dart';
|
part 'space_details_state.dart';
|
||||||
|
|
||||||
class SpaceDetailsBloc extends Bloc<SpaceDetailsEvent, SpaceDetailsState> {
|
class SpaceDetailsBloc extends Bloc<SpaceDetailsEvent, SpaceDetailsState> {
|
||||||
|
final SpaceDetailsService _spaceDetailsService;
|
||||||
|
|
||||||
SpaceDetailsBloc(this._spaceDetailsService) : super(SpaceDetailsInitial()) {
|
SpaceDetailsBloc(this._spaceDetailsService) : super(SpaceDetailsInitial()) {
|
||||||
on<LoadSpaceDetails>(_onLoadSpaceDetails);
|
on<LoadSpaceDetails>(_onLoadSpaceDetails);
|
||||||
on<ClearSpaceDetails>(_onClearSpaceDetails);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final SpaceDetailsService _spaceDetailsService;
|
|
||||||
|
|
||||||
Future<void> _onLoadSpaceDetails(
|
Future<void> _onLoadSpaceDetails(
|
||||||
LoadSpaceDetails event,
|
LoadSpaceDetails event,
|
||||||
Emitter<SpaceDetailsState> emit,
|
Emitter<SpaceDetailsState> emit,
|
||||||
@ -32,11 +31,4 @@ class SpaceDetailsBloc extends Bloc<SpaceDetailsEvent, SpaceDetailsState> {
|
|||||||
emit(SpaceDetailsFailure(e.toString()));
|
emit(SpaceDetailsFailure(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onClearSpaceDetails(
|
|
||||||
ClearSpaceDetails event,
|
|
||||||
Emitter<SpaceDetailsState> emit,
|
|
||||||
) {
|
|
||||||
emit(SpaceDetailsInitial());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,11 @@ sealed class SpaceDetailsEvent extends Equatable {
|
|||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
final class LoadSpaceDetails extends SpaceDetailsEvent {
|
class LoadSpaceDetails extends SpaceDetailsEvent {
|
||||||
const LoadSpaceDetails(this.param);
|
const LoadSpaceDetails(this.param);
|
||||||
|
|
||||||
final LoadSpaceDetailsParam param;
|
final LoadSpacesParam param;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [param];
|
List<Object> get props => [param];
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ClearSpaceDetails extends SpaceDetailsEvent {
|
|
||||||
const ClearSpaceDetails();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [];
|
|
||||||
}
|
|
@ -21,10 +21,10 @@ final class SpaceDetailsLoaded extends SpaceDetailsState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class SpaceDetailsFailure extends SpaceDetailsState {
|
final class SpaceDetailsFailure extends SpaceDetailsState {
|
||||||
final String errorMessage;
|
final String message;
|
||||||
|
|
||||||
const SpaceDetailsFailure(this.errorMessage);
|
const SpaceDetailsFailure(this.message);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [errorMessage];
|
List<Object> get props => [message];
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,11 @@
|
|||||||
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/modules/communities/domain/models/space_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/data/services/remote_space_details_service.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_dialog.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_dialog.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
|
||||||
|
|
||||||
abstract final class SpaceDetailsDialogHelper {
|
abstract final class SpaceDetailsDialogHelper {
|
||||||
static void showCreate(BuildContext context) {
|
static void showCreate(BuildContext context) {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => BlocProvider(
|
builder: (context) => const SpaceDetailsDialog(),
|
||||||
create: (context) => SpaceDetailsBloc(
|
|
||||||
RemoteSpaceDetailsService(httpService: HTTPService()),
|
|
||||||
),
|
|
||||||
child: SpaceDetailsDialog(
|
|
||||||
context: context,
|
|
||||||
title: const Text('Create Space'),
|
|
||||||
spaceModel: SpaceModel.empty(),
|
|
||||||
onSave: print,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void showEdit(
|
|
||||||
BuildContext context, {
|
|
||||||
required SpaceModel spaceModel,
|
|
||||||
}) {
|
|
||||||
showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => BlocProvider(
|
|
||||||
create: (context) => SpaceDetailsBloc(
|
|
||||||
RemoteSpaceDetailsService(httpService: HTTPService()),
|
|
||||||
),
|
|
||||||
child: SpaceDetailsDialog(
|
|
||||||
context: context,
|
|
||||||
title: const Text('Edit Space'),
|
|
||||||
spaceModel: spaceModel,
|
|
||||||
onSave: (space) {},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class ButtonContentWidget extends StatelessWidget {
|
|
||||||
final String label;
|
|
||||||
final String? svgAssets;
|
|
||||||
final bool disabled;
|
|
||||||
|
|
||||||
const ButtonContentWidget({
|
|
||||||
required this.label,
|
|
||||||
this.svgAssets,
|
|
||||||
this.disabled = false,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
|
||||||
|
|
||||||
return Opacity(
|
|
||||||
opacity: disabled ? 0.5 : 1.0,
|
|
||||||
child: Container(
|
|
||||||
width: screenWidth * 0.25,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.textFieldGreyColor,
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.neutralGray,
|
|
||||||
width: 3.0,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 16.0),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
if (svgAssets != null)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 6.0),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
svgAssets!,
|
|
||||||
width: screenWidth * 0.015,
|
|
||||||
height: screenWidth * 0.015,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
label,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorsManager.blackColor,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class SpaceDetailsActionButtons extends StatelessWidget {
|
|
||||||
const SpaceDetailsActionButtons({
|
|
||||||
super.key,
|
|
||||||
required this.onSave,
|
|
||||||
required this.onCancel,
|
|
||||||
});
|
|
||||||
|
|
||||||
final VoidCallback onCancel;
|
|
||||||
final VoidCallback? onSave;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
spacing: 10,
|
|
||||||
children: [
|
|
||||||
Expanded(child: _buildCancelButton(context)),
|
|
||||||
Expanded(child: _buildSaveButton()),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildCancelButton(BuildContext context) {
|
|
||||||
return CancelButton(
|
|
||||||
onPressed: onCancel,
|
|
||||||
label: 'Cancel',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildSaveButton() {
|
|
||||||
return DefaultButton(
|
|
||||||
onPressed: onSave,
|
|
||||||
borderRadius: 10,
|
|
||||||
backgroundColor: ColorsManager.secondaryColor,
|
|
||||||
foregroundColor: ColorsManager.whiteColors,
|
|
||||||
child: const Text('OK'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/common/edit_chip.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/button_content_widget.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class SpaceDetailsDevicesBox extends StatelessWidget {
|
|
||||||
const SpaceDetailsDevicesBox({
|
|
||||||
required this.space,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final SpaceDetailsModel space;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final productAllocations = space.productAllocations;
|
|
||||||
final subspaces = space.subspaces;
|
|
||||||
final isAnySubspaceHasProductAllocations =
|
|
||||||
subspaces.any((subspace) => subspace.productAllocations.isNotEmpty);
|
|
||||||
if (productAllocations.isNotEmpty || isAnySubspaceHasProductAllocations) {
|
|
||||||
return Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.textFieldGreyColor,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.textFieldGreyColor,
|
|
||||||
width: 3.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 8.0,
|
|
||||||
runSpacing: 8.0,
|
|
||||||
children: [
|
|
||||||
// Combine tags from spaceModel and subspaces
|
|
||||||
// ...TagHelper.groupTags([
|
|
||||||
// ...?tags,
|
|
||||||
// ...?subspaces?.expand((subspace) => subspace.tags ?? [])
|
|
||||||
// ]).entries.map(
|
|
||||||
// (entry) => Chip(
|
|
||||||
// avatar: SizedBox(
|
|
||||||
// width: 24,
|
|
||||||
// height: 24,
|
|
||||||
// child: SvgPicture.asset(
|
|
||||||
// entry.key.icon ?? 'assets/icons/gateway.svg',
|
|
||||||
// fit: BoxFit.contain,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// label: Text(
|
|
||||||
// 'x${entry.value}',
|
|
||||||
// style: Theme.of(context)
|
|
||||||
// .textTheme
|
|
||||||
// .bodySmall
|
|
||||||
// ?.copyWith(color: ColorsManager.spaceColor),
|
|
||||||
// ),
|
|
||||||
// backgroundColor: ColorsManager.whiteColors,
|
|
||||||
// shape: RoundedRectangleBorder(
|
|
||||||
// borderRadius: BorderRadius.circular(16),
|
|
||||||
// side: const BorderSide(
|
|
||||||
// color: ColorsManager.spaceColor,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
|
|
||||||
EditChip(
|
|
||||||
onTap: () {},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return TextButton(
|
|
||||||
onPressed: () {},
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
),
|
|
||||||
child: const SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: ButtonContentWidget(
|
|
||||||
svgAssets: Assets.addIcon,
|
|
||||||
label: 'Add Devices',
|
|
||||||
// disabled: isTagsAndSubspaceModelDisabled,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +1,12 @@
|
|||||||
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/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';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_form.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class SpaceDetailsDialog extends StatefulWidget {
|
class SpaceDetailsDialog extends StatelessWidget {
|
||||||
const SpaceDetailsDialog({
|
const SpaceDetailsDialog({super.key});
|
||||||
required this.title,
|
|
||||||
required this.spaceModel,
|
|
||||||
required this.onSave,
|
|
||||||
required this.context,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Widget title;
|
|
||||||
final SpaceModel spaceModel;
|
|
||||||
final void Function(SpaceDetailsModel space) onSave;
|
|
||||||
final BuildContext context;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SpaceDetailsDialog> createState() => _SpaceDetailsDialogState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SpaceDetailsDialogState extends State<SpaceDetailsDialog> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
final isCreateMode = widget.spaceModel.uuid.isEmpty;
|
|
||||||
|
|
||||||
if (!isCreateMode) {
|
|
||||||
final param = LoadSpaceDetailsParam(
|
|
||||||
spaceUuid: widget.spaceModel.uuid,
|
|
||||||
communityUuid: widget.context
|
|
||||||
.read<CommunitiesTreeSelectionBloc>()
|
|
||||||
.state
|
|
||||||
.selectedCommunity!
|
|
||||||
.uuid,
|
|
||||||
);
|
|
||||||
widget.context.read<SpaceDetailsBloc>().add(LoadSpaceDetails(param));
|
|
||||||
}
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isCreateMode = widget.spaceModel.uuid.isEmpty;
|
return const Dialog(
|
||||||
if (isCreateMode) {
|
child: Text('Create Space'),
|
||||||
return SpaceDetailsForm(
|
|
||||||
title: widget.title,
|
|
||||||
space: SpaceDetailsModel.empty(),
|
|
||||||
onSave: widget.onSave,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BlocBuilder<SpaceDetailsBloc, SpaceDetailsState>(
|
|
||||||
bloc: widget.context.read<SpaceDetailsBloc>(),
|
|
||||||
builder: (context, state) => switch (state) {
|
|
||||||
SpaceDetailsInitial() => _buildLoadingDialog(),
|
|
||||||
SpaceDetailsLoading() => _buildLoadingDialog(),
|
|
||||||
SpaceDetailsLoaded(:final spaceDetails) => SpaceDetailsForm(
|
|
||||||
title: widget.title,
|
|
||||||
space: spaceDetails,
|
|
||||||
onSave: widget.onSave,
|
|
||||||
),
|
|
||||||
SpaceDetailsFailure(:final errorMessage) => _buildErrorDialog(
|
|
||||||
errorMessage,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildLoadingDialog() {
|
|
||||||
return AlertDialog(
|
|
||||||
title: widget.title,
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
content: const Center(child: CircularProgressIndicator()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildErrorDialog(String errorMessage) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: widget.title,
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
content: Center(
|
|
||||||
child: SelectableText(
|
|
||||||
errorMessage,
|
|
||||||
style: context.textTheme.bodyLarge?.copyWith(
|
|
||||||
color: ColorsManager.red,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
fontSize: 18,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_devices_box.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_icon_picker.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_name_text_field.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_box.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class SpaceDetailsForm extends StatelessWidget {
|
|
||||||
const SpaceDetailsForm({
|
|
||||||
required this.title,
|
|
||||||
required this.space,
|
|
||||||
required this.onSave,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Widget title;
|
|
||||||
final SpaceDetailsModel space;
|
|
||||||
final void Function(SpaceDetailsModel space) onSave;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocProvider(
|
|
||||||
create: (context) => SpaceDetailsModelBloc(initialState: space),
|
|
||||||
child: BlocBuilder<SpaceDetailsModelBloc, SpaceDetailsModel>(
|
|
||||||
buildWhen: (previous, current) => previous != current,
|
|
||||||
builder: (context, state) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: title,
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
content: SizedBox(
|
|
||||||
height: context.screenHeight * 0.3,
|
|
||||||
width: context.screenWidth * 0.5,
|
|
||||||
child: Row(
|
|
||||||
spacing: 20,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(child: SpaceIconPicker(iconPath: state.icon)),
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SpaceNameTextField(
|
|
||||||
initialValue: state.spaceName,
|
|
||||||
isNameFieldExist: (value) => state.subspaces.any(
|
|
||||||
(subspace) => subspace.name == value,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
SpaceSubSpacesBox(
|
|
||||||
subspaces: state.subspaces,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
SpaceDetailsDevicesBox(space: state),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
SpaceDetailsActionButtons(
|
|
||||||
onSave: () => onSave(state),
|
|
||||||
onCancel: Navigator.of(context).pop,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_icon_selection_dialog.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class SpaceIconPicker extends StatelessWidget {
|
|
||||||
const SpaceIconPicker({
|
|
||||||
required this.iconPath,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String iconPath;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Center(
|
|
||||||
child: Stack(
|
|
||||||
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: context.screenWidth * 0.175,
|
|
||||||
height: context.screenHeight * 0.175,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: ColorsManager.boxColor,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.all(24),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
iconPath,
|
|
||||||
width: context.screenWidth * 0.08,
|
|
||||||
height: context.screenHeight * 0.08,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned.directional(
|
|
||||||
top: 12,
|
|
||||||
start: context.screenHeight * 0.06,
|
|
||||||
textDirection: Directionality.of(context),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
showDialog<String?>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => SpaceIconSelectionDialog(
|
|
||||||
selectedIcon: iconPath,
|
|
||||||
),
|
|
||||||
).then((value) {
|
|
||||||
if (value != null) {
|
|
||||||
if (context.mounted) {
|
|
||||||
context.read<SpaceDetailsModelBloc>().add(
|
|
||||||
UpdateSpaceDetailsIcon(value),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
Assets.iconEdit,
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class SpaceIconSelectionDialog extends StatelessWidget {
|
|
||||||
const SpaceIconSelectionDialog({super.key, required this.selectedIcon});
|
|
||||||
final String selectedIcon;
|
|
||||||
|
|
||||||
static const List<String> _icons = [
|
|
||||||
Assets.location,
|
|
||||||
Assets.villa,
|
|
||||||
Assets.gym,
|
|
||||||
Assets.sauna,
|
|
||||||
Assets.bbq,
|
|
||||||
Assets.building,
|
|
||||||
Assets.desk,
|
|
||||||
Assets.door,
|
|
||||||
Assets.parking,
|
|
||||||
Assets.pool,
|
|
||||||
Assets.stair,
|
|
||||||
Assets.steamRoom,
|
|
||||||
Assets.street,
|
|
||||||
Assets.unit,
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: SelectableText(
|
|
||||||
'Space Icon',
|
|
||||||
style: context.textTheme.headlineMedium,
|
|
||||||
),
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
content: Container(
|
|
||||||
width: context.screenWidth * 0.45,
|
|
||||||
height: context.screenHeight * 0.275,
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.boxColor,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: GridView.builder(
|
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 7,
|
|
||||||
crossAxisSpacing: 8,
|
|
||||||
mainAxisSpacing: 16,
|
|
||||||
),
|
|
||||||
itemCount: _icons.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final isSelected = selectedIcon == _icons[index];
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsetsDirectional.all(2),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
border: isSelected
|
|
||||||
? Border.all(color: ColorsManager.vividBlue, width: 2)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(_icons[index]),
|
|
||||||
icon: SvgPicture.asset(
|
|
||||||
_icons[index],
|
|
||||||
width: context.screenWidth * 0.03,
|
|
||||||
height: context.screenHeight * 0.08,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class SpaceNameTextField extends StatefulWidget {
|
|
||||||
const SpaceNameTextField({
|
|
||||||
required this.initialValue,
|
|
||||||
required this.isNameFieldExist,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String? initialValue;
|
|
||||||
final bool Function(String value) isNameFieldExist;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SpaceNameTextField> createState() => _SpaceNameTextFieldState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SpaceNameTextFieldState extends State<SpaceNameTextField> {
|
|
||||||
late final TextEditingController _controller;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
_controller = TextEditingController(text: widget.initialValue);
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
|
||||||
|
|
||||||
String? _validateName(String? value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return '*Space name should not be empty.';
|
|
||||||
}
|
|
||||||
if (widget.isNameFieldExist(value)) {
|
|
||||||
return '*Name already exists';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Form(
|
|
||||||
key: _formKey,
|
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _controller,
|
|
||||||
onChanged: (value) => context.read<SpaceDetailsModelBloc>().add(
|
|
||||||
UpdateSpaceDetailsName(value),
|
|
||||||
),
|
|
||||||
validator: _validateName,
|
|
||||||
style: context.textTheme.bodyMedium,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Please enter the name',
|
|
||||||
hintStyle: context.textTheme.bodyMedium!.copyWith(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
),
|
|
||||||
filled: true,
|
|
||||||
fillColor: ColorsManager.boxColor,
|
|
||||||
enabledBorder: _buildBorder(context, ColorsManager.vividBlue),
|
|
||||||
focusedBorder: _buildBorder(context, ColorsManager.primaryColor),
|
|
||||||
errorBorder: _buildBorder(context, context.theme.colorScheme.error),
|
|
||||||
focusedErrorBorder: _buildBorder(context, context.theme.colorScheme.error),
|
|
||||||
errorStyle: context.textTheme.bodySmall?.copyWith(
|
|
||||||
color: context.theme.colorScheme.error,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
OutlineInputBorder _buildBorder(BuildContext context, [Color? color]) {
|
|
||||||
return OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
borderSide: BorderSide(width: 1, color: color ?? ColorsManager.boxColor),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/common/edit_chip.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/button_content_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_dialog.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/subspace_name_display_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class SpaceSubSpacesBox extends StatelessWidget {
|
|
||||||
const SpaceSubSpacesBox({super.key, required this.subspaces});
|
|
||||||
|
|
||||||
final List<Subspace> subspaces;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (subspaces.isEmpty) {
|
|
||||||
return TextButton(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
overlayColor: ColorsManager.transparentColor,
|
|
||||||
),
|
|
||||||
onPressed: () => _showSubSpacesDialog(context),
|
|
||||||
child: const SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: ButtonContentWidget(
|
|
||||||
svgAssets: Assets.addIcon,
|
|
||||||
label: 'Create Sub Spaces',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
width: double.infinity,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.textFieldGreyColor,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.textFieldGreyColor,
|
|
||||||
width: 3.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 8.0,
|
|
||||||
runSpacing: 8.0,
|
|
||||||
children: [
|
|
||||||
...subspaces.map((e) => SubspaceNameDisplayWidget(subSpace: e)),
|
|
||||||
EditChip(
|
|
||||||
onTap: () => _showSubSpacesDialog(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showSubSpacesDialog(BuildContext context) {
|
|
||||||
showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (_) => SpaceSubSpacesDialog(
|
|
||||||
subspaces: subspaces,
|
|
||||||
onSave: (subspaces) {
|
|
||||||
context.read<SpaceDetailsModelBloc>().add(
|
|
||||||
UpdateSpaceDetailsSubspaces(subspaces),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/sub_spaces_input.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class SpaceSubSpacesDialog extends StatefulWidget {
|
|
||||||
const SpaceSubSpacesDialog({
|
|
||||||
required this.subspaces,
|
|
||||||
required this.onSave,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final List<Subspace> subspaces;
|
|
||||||
final void Function(List<Subspace> subspaces) onSave;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SpaceSubSpacesDialog> createState() => _SpaceSubSpacesDialogState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SpaceSubSpacesDialogState extends State<SpaceSubSpacesDialog> {
|
|
||||||
late List<Subspace> _subspaces;
|
|
||||||
|
|
||||||
bool get _hasDuplicateNames =>
|
|
||||||
_subspaces.map((subspace) => subspace.name.toLowerCase()).toSet().length !=
|
|
||||||
_subspaces.length;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_subspaces = List.from(widget.subspaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleSubspaceAdded(String name) {
|
|
||||||
setState(() {
|
|
||||||
_subspaces = [
|
|
||||||
..._subspaces,
|
|
||||||
Subspace(
|
|
||||||
name: name,
|
|
||||||
uuid: const Uuid().v4(),
|
|
||||||
productAllocations: const [],
|
|
||||||
),
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleSubspaceDeleted(String uuid) => setState(
|
|
||||||
() => _subspaces = _subspaces.where((s) => s.uuid != uuid).toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
void _handleSave() {
|
|
||||||
widget.onSave(_subspaces);
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: const Text('Create Sub Spaces'),
|
|
||||||
content: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SubSpacesInput(
|
|
||||||
subSpaces: _subspaces,
|
|
||||||
onSubspaceAdded: _handleSubspaceAdded,
|
|
||||||
onSubspaceDeleted: _handleSubspaceDeleted,
|
|
||||||
),
|
|
||||||
AnimatedSwitcher(
|
|
||||||
duration: const Duration(milliseconds: 100),
|
|
||||||
child: Visibility(
|
|
||||||
key: ValueKey(_hasDuplicateNames),
|
|
||||||
visible: _hasDuplicateNames,
|
|
||||||
child: const Text(
|
|
||||||
'Error: Duplicate subspace names are not allowed.',
|
|
||||||
style: TextStyle(color: Colors.red),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
SpaceDetailsActionButtons(
|
|
||||||
onSave: _hasDuplicateNames ? null : _handleSave,
|
|
||||||
onCancel: Navigator.of(context).pop,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/subspace_chip.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class SubSpacesInput extends StatefulWidget {
|
|
||||||
const SubSpacesInput({
|
|
||||||
super.key,
|
|
||||||
required this.subSpaces,
|
|
||||||
required this.onSubspaceAdded,
|
|
||||||
required this.onSubspaceDeleted,
|
|
||||||
});
|
|
||||||
|
|
||||||
final List<Subspace> subSpaces;
|
|
||||||
final void Function(String name) onSubspaceAdded;
|
|
||||||
final void Function(String uuid) onSubspaceDeleted;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SubSpacesInput> createState() => _SubSpacesInputState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SubSpacesInputState extends State<SubSpacesInput> {
|
|
||||||
late final TextEditingController _subspaceNameController;
|
|
||||||
late final FocusNode _focusNode;
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_subspaceNameController = TextEditingController();
|
|
||||||
_focusNode = FocusNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_subspaceNameController.dispose();
|
|
||||||
_focusNode.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
width: context.screenWidth * 0.35,
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 10,
|
|
||||||
horizontal: 16,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.boxColor,
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 8,
|
|
||||||
runSpacing: 8,
|
|
||||||
alignment: WrapAlignment.start,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
|
||||||
...widget.subSpaces.asMap().entries.map(
|
|
||||||
(entry) {
|
|
||||||
final index = entry.key;
|
|
||||||
final subSpace = entry.value;
|
|
||||||
|
|
||||||
final lowerName = subSpace.name.toLowerCase();
|
|
||||||
|
|
||||||
final duplicateIndices = widget.subSpaces
|
|
||||||
.asMap()
|
|
||||||
.entries
|
|
||||||
.where((e) => e.value.name.toLowerCase() == lowerName)
|
|
||||||
.map((e) => e.key)
|
|
||||||
.toList();
|
|
||||||
final isDuplicate = duplicateIndices.length > 1 &&
|
|
||||||
duplicateIndices.indexOf(index) != 0;
|
|
||||||
return SubspaceChip(
|
|
||||||
subSpace: subSpace,
|
|
||||||
isDuplicate: isDuplicate,
|
|
||||||
onDeleted: () => widget.onSubspaceDeleted(subSpace.uuid),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 200,
|
|
||||||
child: TextField(
|
|
||||||
focusNode: _focusNode,
|
|
||||||
controller: _subspaceNameController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
border: InputBorder.none,
|
|
||||||
hintText: widget.subSpaces.isEmpty ? 'Please enter the name' : null,
|
|
||||||
hintStyle: context.textTheme.bodySmall?.copyWith(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onSubmitted: (value) {
|
|
||||||
final trimmedValue = value.trim();
|
|
||||||
if (trimmedValue.isNotEmpty) {
|
|
||||||
widget.onSubspaceAdded(trimmedValue);
|
|
||||||
_subspaceNameController.clear();
|
|
||||||
_focusNode.requestFocus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
style: context.textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class SubspaceChip extends StatelessWidget {
|
|
||||||
const SubspaceChip({
|
|
||||||
required this.subSpace,
|
|
||||||
required this.isDuplicate,
|
|
||||||
required this.onDeleted,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Subspace subSpace;
|
|
||||||
final bool isDuplicate;
|
|
||||||
final void Function() onDeleted;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Chip(
|
|
||||||
label: Text(
|
|
||||||
subSpace.name,
|
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
|
||||||
color: isDuplicate ? ColorsManager.red : ColorsManager.spaceColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
side: BorderSide(
|
|
||||||
color: isDuplicate ? ColorsManager.red : ColorsManager.transparentColor,
|
|
||||||
width: 0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
deleteIcon: Container(
|
|
||||||
padding: const EdgeInsetsDirectional.all(1),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
width: 1.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const FittedBox(
|
|
||||||
fit: BoxFit.scaleDown,
|
|
||||||
child: Icon(
|
|
||||||
Icons.close,
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onDeleted: onDeleted,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,171 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class SubspaceNameDisplayWidget extends StatefulWidget {
|
|
||||||
const SubspaceNameDisplayWidget({super.key, required this.subSpace});
|
|
||||||
|
|
||||||
final Subspace subSpace;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SubspaceNameDisplayWidget> createState() =>
|
|
||||||
_SubspaceNameDisplayWidgetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SubspaceNameDisplayWidgetState extends State<SubspaceNameDisplayWidget> {
|
|
||||||
late final TextEditingController _controller;
|
|
||||||
late final FocusNode _focusNode;
|
|
||||||
bool _isEditing = false;
|
|
||||||
bool _hasDuplicateName = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
_controller = TextEditingController(text: widget.subSpace.name);
|
|
||||||
_focusNode = FocusNode();
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
_focusNode.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _checkForDuplicateName(String name) {
|
|
||||||
final bloc = context.read<SpaceDetailsModelBloc>();
|
|
||||||
return bloc.state.subspaces
|
|
||||||
.where((s) => s.uuid != widget.subSpace.uuid)
|
|
||||||
.any((s) => s.name.toLowerCase() == name.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleNameChange(String value) {
|
|
||||||
setState(() {
|
|
||||||
_hasDuplicateName = _checkForDuplicateName(value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _tryToFinishEditing() {
|
|
||||||
if (!_hasDuplicateName) {
|
|
||||||
_onFinishEditing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _tryToSubmit(String value) {
|
|
||||||
if (_hasDuplicateName) return;
|
|
||||||
|
|
||||||
final bloc = context.read<SpaceDetailsModelBloc>();
|
|
||||||
bloc.add(
|
|
||||||
UpdateSpaceDetailsSubspaces(
|
|
||||||
bloc.state.subspaces
|
|
||||||
.map(
|
|
||||||
(e) => e.uuid == widget.subSpace.uuid ? e.copyWith(name: value) : e,
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
_onFinishEditing();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final textStyle = context.textTheme.bodySmall?.copyWith(
|
|
||||||
color: ColorsManager.spaceColor,
|
|
||||||
);
|
|
||||||
return InkWell(
|
|
||||||
onTap: () {
|
|
||||||
setState(() => _isEditing = true);
|
|
||||||
_focusNode.requestFocus();
|
|
||||||
},
|
|
||||||
child: Chip(
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
side: const BorderSide(color: ColorsManager.transparentColor),
|
|
||||||
),
|
|
||||||
onDeleted: () {
|
|
||||||
final bloc = context.read<SpaceDetailsModelBloc>();
|
|
||||||
bloc.add(
|
|
||||||
UpdateSpaceDetailsSubspaces(
|
|
||||||
bloc.state.subspaces
|
|
||||||
.where((s) => s.uuid != widget.subSpace.uuid)
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
deleteIcon: Container(
|
|
||||||
padding: const EdgeInsetsDirectional.all(1),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
width: 1.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const FittedBox(
|
|
||||||
child: Icon(
|
|
||||||
Icons.close,
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
label: Visibility(
|
|
||||||
visible: _isEditing,
|
|
||||||
replacement: Text(
|
|
||||||
widget.subSpace.name,
|
|
||||||
style: textStyle,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: context.screenWidth * 0.065,
|
|
||||||
height: context.screenHeight * 0.025,
|
|
||||||
child: TextField(
|
|
||||||
focusNode: _focusNode,
|
|
||||||
controller: _controller,
|
|
||||||
style: textStyle?.copyWith(
|
|
||||||
color: _hasDuplicateName ? Colors.red : null,
|
|
||||||
),
|
|
||||||
decoration: const InputDecoration.collapsed(
|
|
||||||
hintText: '',
|
|
||||||
),
|
|
||||||
onChanged: _handleNameChange,
|
|
||||||
onTapOutside: (_) => _tryToFinishEditing(),
|
|
||||||
onSubmitted: _tryToSubmit,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_hasDuplicateName)
|
|
||||||
AnimatedSwitcher(
|
|
||||||
duration: const Duration(milliseconds: 250),
|
|
||||||
child: Visibility(
|
|
||||||
key: ValueKey(_hasDuplicateName),
|
|
||||||
visible: _hasDuplicateName,
|
|
||||||
child: Text(
|
|
||||||
'Name already exists',
|
|
||||||
style: textStyle?.copyWith(
|
|
||||||
color: Colors.red,
|
|
||||||
fontSize: 8,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onFinishEditing() {
|
|
||||||
setState(() {
|
|
||||||
_isEditing = false;
|
|
||||||
_hasDuplicateName = false;
|
|
||||||
});
|
|
||||||
_focusNode.unfocus();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
|
|
||||||
part 'space_details_model_event.dart';
|
|
||||||
|
|
||||||
class SpaceDetailsModelBloc extends Bloc<SpaceDetailsModelEvent, SpaceDetailsModel> {
|
|
||||||
SpaceDetailsModelBloc({
|
|
||||||
required SpaceDetailsModel initialState,
|
|
||||||
}) : super(initialState) {
|
|
||||||
on<UpdateSpaceDetailsIcon>(_onUpdateSpaceDetailsIcon);
|
|
||||||
on<UpdateSpaceDetailsName>(_onUpdateSpaceDetailsName);
|
|
||||||
on<UpdateSpaceDetailsSubspaces>(_onUpdateSpaceDetailsSubspaces);
|
|
||||||
on<UpdateSpaceDetailsProductAllocations>(
|
|
||||||
_onUpdateSpaceDetailsProductAllocations);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onUpdateSpaceDetailsIcon(
|
|
||||||
UpdateSpaceDetailsIcon event,
|
|
||||||
Emitter<SpaceDetailsModel> emit,
|
|
||||||
) {
|
|
||||||
emit(state.copyWith(icon: event.icon));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onUpdateSpaceDetailsName(
|
|
||||||
UpdateSpaceDetailsName event,
|
|
||||||
Emitter<SpaceDetailsModel> emit,
|
|
||||||
) {
|
|
||||||
emit(state.copyWith(spaceName: event.name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onUpdateSpaceDetailsSubspaces(
|
|
||||||
UpdateSpaceDetailsSubspaces event,
|
|
||||||
Emitter<SpaceDetailsModel> emit,
|
|
||||||
) {
|
|
||||||
emit(state.copyWith(subspaces: event.subspaces));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onUpdateSpaceDetailsProductAllocations(
|
|
||||||
UpdateSpaceDetailsProductAllocations event,
|
|
||||||
Emitter<SpaceDetailsModel> emit,
|
|
||||||
) {
|
|
||||||
emit(state.copyWith(productAllocations: event.productAllocations));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
part of 'space_details_model_bloc.dart';
|
|
||||||
|
|
||||||
sealed class SpaceDetailsModelEvent extends Equatable {
|
|
||||||
const SpaceDetailsModelEvent();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [];
|
|
||||||
}
|
|
||||||
|
|
||||||
final class UpdateSpaceDetailsIcon extends SpaceDetailsModelEvent {
|
|
||||||
const UpdateSpaceDetailsIcon(this.icon);
|
|
||||||
|
|
||||||
final String icon;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [icon];
|
|
||||||
}
|
|
||||||
|
|
||||||
final class UpdateSpaceDetailsName extends SpaceDetailsModelEvent {
|
|
||||||
const UpdateSpaceDetailsName(this.name);
|
|
||||||
|
|
||||||
final String name;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [name];
|
|
||||||
}
|
|
||||||
|
|
||||||
final class UpdateSpaceDetailsSubspaces extends SpaceDetailsModelEvent {
|
|
||||||
const UpdateSpaceDetailsSubspaces(this.subspaces);
|
|
||||||
|
|
||||||
final List<Subspace> subspaces;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [subspaces];
|
|
||||||
}
|
|
||||||
|
|
||||||
final class UpdateSpaceDetailsProductAllocations extends SpaceDetailsModelEvent {
|
|
||||||
const UpdateSpaceDetailsProductAllocations(this.productAllocations);
|
|
||||||
|
|
||||||
final List<ProductAllocation> productAllocations;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [productAllocations];
|
|
||||||
}
|
|
@ -52,7 +52,4 @@ final myTheme = ThemeData(
|
|||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dialogTheme: const DialogThemeData(
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user