mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
space model view
This commit is contained in:
@ -4,17 +4,20 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_mod
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/services/product_api.dart';
|
import 'package:syncrow_web/services/product_api.dart';
|
||||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
|
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||||
|
|
||||||
class SpaceManagementBloc
|
class SpaceManagementBloc
|
||||||
extends Bloc<SpaceManagementEvent, SpaceManagementState> {
|
extends Bloc<SpaceManagementEvent, SpaceManagementState> {
|
||||||
final CommunitySpaceManagementApi _api;
|
final CommunitySpaceManagementApi _api;
|
||||||
final ProductApi _productApi;
|
final ProductApi _productApi;
|
||||||
|
final SpaceModelManagementApi _spaceModelApi;
|
||||||
|
|
||||||
List<ProductModel>? _cachedProducts;
|
List<ProductModel>? _cachedProducts;
|
||||||
|
|
||||||
SpaceManagementBloc(this._api, this._productApi)
|
SpaceManagementBloc(this._api, this._productApi, this._spaceModelApi)
|
||||||
: super(SpaceManagementInitial()) {
|
: super(SpaceManagementInitial()) {
|
||||||
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
|
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
|
||||||
on<UpdateSpacePositionEvent>(_onUpdateSpacePosition);
|
on<UpdateSpacePositionEvent>(_onUpdateSpacePosition);
|
||||||
@ -27,6 +30,7 @@ class SpaceManagementBloc
|
|||||||
on<SelectSpaceEvent>(_onSelectSpace);
|
on<SelectSpaceEvent>(_onSelectSpace);
|
||||||
on<NewCommunityEvent>(_onNewCommunity);
|
on<NewCommunityEvent>(_onNewCommunity);
|
||||||
on<BlankStateEvent>(_onBlankState);
|
on<BlankStateEvent>(_onBlankState);
|
||||||
|
on<SpaceModelLoadEvent>(_onLoadSpaceModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateCommunity(
|
void _onUpdateCommunity(
|
||||||
@ -410,4 +414,37 @@ class SpaceManagementBloc
|
|||||||
}
|
}
|
||||||
return result.toList(); // Convert back to a list
|
return result.toList(); // Convert back to a list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onLoadSpaceModel(
|
||||||
|
SpaceModelLoadEvent event, Emitter<SpaceManagementState> emit) async {
|
||||||
|
emit(SpaceManagementLoading());
|
||||||
|
try {
|
||||||
|
List<CommunityModel> communities = await _api.fetchCommunities();
|
||||||
|
|
||||||
|
List<CommunityModel> updatedCommunities = await Future.wait(
|
||||||
|
communities.map((community) async {
|
||||||
|
List<SpaceModel> spaces =
|
||||||
|
await _fetchSpacesForCommunity(community.uuid);
|
||||||
|
return CommunityModel(
|
||||||
|
uuid: community.uuid,
|
||||||
|
createdAt: community.createdAt,
|
||||||
|
updatedAt: community.updatedAt,
|
||||||
|
name: community.name,
|
||||||
|
description: community.description,
|
||||||
|
spaces: spaces, // New spaces list
|
||||||
|
region: community.region,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<SpaceTemplateModel> spaceModels =
|
||||||
|
await _spaceModelApi.listSpaceModels(page: 1);
|
||||||
|
emit(SpaceModelLoaded(
|
||||||
|
communities: updatedCommunities,
|
||||||
|
products: _cachedProducts ?? [],
|
||||||
|
spaceModels: spaceModels));
|
||||||
|
} catch (e) {
|
||||||
|
emit(SpaceManagementError('Error loading communities and spaces: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,3 +143,5 @@ class LoadSpaceHierarchyEvent extends SpaceManagementEvent {
|
|||||||
|
|
||||||
|
|
||||||
class BlankStateEvent extends SpaceManagementEvent {}
|
class BlankStateEvent extends SpaceManagementEvent {}
|
||||||
|
|
||||||
|
class SpaceModelLoadEvent extends SpaceManagementEvent {}
|
||||||
|
@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
|
||||||
abstract class SpaceManagementState extends Equatable {
|
abstract class SpaceManagementState extends Equatable {
|
||||||
const SpaceManagementState();
|
const SpaceManagementState();
|
||||||
@ -27,6 +28,10 @@ class SpaceManagementLoaded extends SpaceManagementState {
|
|||||||
this.selectedSpace});
|
this.selectedSpace});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SpaceModelManagenetLoaded extends SpaceManagementState {
|
||||||
|
SpaceModelManagenetLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
class BlankState extends SpaceManagementState {
|
class BlankState extends SpaceManagementState {
|
||||||
final List<CommunityModel> communities;
|
final List<CommunityModel> communities;
|
||||||
final List<ProductModel> products;
|
final List<ProductModel> products;
|
||||||
@ -54,3 +59,18 @@ class SpaceManagementError extends SpaceManagementState {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [errorMessage];
|
List<Object> get props => [errorMessage];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SpaceModelLoaded extends SpaceManagementState {
|
||||||
|
final List<SpaceTemplateModel> spaceModels;
|
||||||
|
final List<ProductModel> products;
|
||||||
|
final List<CommunityModel> communities;
|
||||||
|
|
||||||
|
SpaceModelLoaded({
|
||||||
|
required this.communities,
|
||||||
|
required this.products,
|
||||||
|
required this.spaceModels,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [communities, products, spaceModels];
|
||||||
|
}
|
||||||
|
@ -19,7 +19,6 @@ class ProductModel {
|
|||||||
|
|
||||||
// Factory method to create a Product from JSON
|
// Factory method to create a Product from JSON
|
||||||
factory ProductModel.fromMap(Map<String, dynamic> json) {
|
factory ProductModel.fromMap(Map<String, dynamic> json) {
|
||||||
String icon = _mapIconToProduct(json['prodType']);
|
|
||||||
return ProductModel(
|
return ProductModel(
|
||||||
uuid: json['uuid'],
|
uuid: json['uuid'],
|
||||||
catName: json['catName'],
|
catName: json['catName'],
|
||||||
|
@ -9,9 +9,9 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/loaded_sp
|
|||||||
import 'package:syncrow_web/pages/spaces_management/structure_selector/view/center_body_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/structure_selector/view/center_body_widget.dart';
|
||||||
import 'package:syncrow_web/services/product_api.dart';
|
import 'package:syncrow_web/services/product_api.dart';
|
||||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
|
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
|
|
||||||
class SpaceManagementPage extends StatefulWidget {
|
class SpaceManagementPage extends StatefulWidget {
|
||||||
const SpaceManagementPage({super.key});
|
const SpaceManagementPage({super.key});
|
||||||
|
|
||||||
@ -22,13 +22,13 @@ class SpaceManagementPage extends StatefulWidget {
|
|||||||
class SpaceManagementPageState extends State<SpaceManagementPage> {
|
class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||||
final CommunitySpaceManagementApi _api = CommunitySpaceManagementApi();
|
final CommunitySpaceManagementApi _api = CommunitySpaceManagementApi();
|
||||||
final ProductApi _productApi = ProductApi();
|
final ProductApi _productApi = ProductApi();
|
||||||
|
final SpaceModelManagementApi _spaceModelApi = SpaceModelManagementApi();
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (_) => SpaceManagementBloc(_api, _productApi)
|
create: (_) => SpaceManagementBloc(_api, _productApi, _spaceModelApi)
|
||||||
..add(LoadCommunityAndSpacesEvent()),
|
..add(LoadCommunityAndSpacesEvent()),
|
||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
@ -59,7 +59,10 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
|||||||
selectedSpace: state.selectedSpace,
|
selectedSpace: state.selectedSpace,
|
||||||
products: state.products,
|
products: state.products,
|
||||||
);
|
);
|
||||||
} else if (state is SpaceManagementError) {
|
}else if(state is SpaceModelLoaded){
|
||||||
|
return LoadedSpaceView(communities: state.communities, products: state.products, spaceModels: state.spaceModels);
|
||||||
|
}
|
||||||
|
else if (state is SpaceManagementError) {
|
||||||
return Center(child: Text('Error: ${state.errorMessage}'));
|
return Center(child: Text('Error: ${state.errorMessage}'));
|
||||||
}
|
}
|
||||||
return Container();
|
return Container();
|
||||||
|
@ -5,12 +5,15 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_structure_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_structure_widget.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/gradient_canvas_border_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/gradient_canvas_border_widget.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/view/space_model_page.dart';
|
||||||
|
|
||||||
class LoadedSpaceView extends StatefulWidget {
|
class LoadedSpaceView extends StatefulWidget {
|
||||||
final List<CommunityModel> communities;
|
final List<CommunityModel> communities;
|
||||||
final CommunityModel? selectedCommunity;
|
final CommunityModel? selectedCommunity;
|
||||||
final SpaceModel? selectedSpace;
|
final SpaceModel? selectedSpace;
|
||||||
final List<ProductModel>? products;
|
final List<ProductModel>? products;
|
||||||
|
final List<SpaceTemplateModel>? spaceModels;
|
||||||
|
|
||||||
const LoadedSpaceView({
|
const LoadedSpaceView({
|
||||||
super.key,
|
super.key,
|
||||||
@ -18,6 +21,7 @@ class LoadedSpaceView extends StatefulWidget {
|
|||||||
this.selectedCommunity,
|
this.selectedCommunity,
|
||||||
this.selectedSpace,
|
this.selectedSpace,
|
||||||
this.products,
|
this.products,
|
||||||
|
this.spaceModels,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -27,6 +31,9 @@ class LoadedSpaceView extends StatefulWidget {
|
|||||||
class _LoadedStateViewState extends State<LoadedSpaceView> {
|
class _LoadedStateViewState extends State<LoadedSpaceView> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final bool hasSpaceModels =
|
||||||
|
widget.spaceModels != null && widget.spaceModels!.isNotEmpty;
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
@ -38,13 +45,18 @@ class _LoadedStateViewState extends State<LoadedSpaceView> {
|
|||||||
widget.selectedCommunity?.uuid ??
|
widget.selectedCommunity?.uuid ??
|
||||||
'',
|
'',
|
||||||
),
|
),
|
||||||
CommunityStructureArea(
|
hasSpaceModels
|
||||||
selectedCommunity: widget.selectedCommunity,
|
? Expanded(
|
||||||
selectedSpace: widget.selectedSpace,
|
child: SpaceModelPage(
|
||||||
spaces: widget.selectedCommunity?.spaces ?? [],
|
spaceModels: widget.spaceModels ??[],
|
||||||
products: widget.products,
|
))
|
||||||
communities: widget.communities,
|
: CommunityStructureArea(
|
||||||
),
|
selectedCommunity: widget.selectedCommunity,
|
||||||
|
selectedSpace: widget.selectedSpace,
|
||||||
|
spaces: widget.selectedCommunity?.spaces ?? [],
|
||||||
|
products: widget.products,
|
||||||
|
communities: widget.communities,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const GradientCanvasBorderWidget(),
|
const GradientCanvasBorderWidget(),
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
|
|
||||||
|
class SpaceTemplateModel {
|
||||||
|
final String uuid;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final String modelName;
|
||||||
|
final bool disabled;
|
||||||
|
final List<SubspaceModel> subspaceModels;
|
||||||
|
final List<TagModel> tags;
|
||||||
|
|
||||||
|
SpaceTemplateModel({
|
||||||
|
required this.uuid,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.modelName,
|
||||||
|
required this.disabled,
|
||||||
|
required this.subspaceModels,
|
||||||
|
required this.tags,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory SpaceTemplateModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return SpaceTemplateModel(
|
||||||
|
uuid: json['uuid'] ?? '',
|
||||||
|
createdAt: DateTime.parse(json['createdAt']),
|
||||||
|
updatedAt: DateTime.parse(json['updatedAt']),
|
||||||
|
modelName: json['modelName'] ?? '',
|
||||||
|
disabled: json['disabled'] ?? false,
|
||||||
|
subspaceModels: (json['subspaceModels'] as List)
|
||||||
|
.map((item) => SubspaceModel.fromJson(item))
|
||||||
|
.toList(),
|
||||||
|
tags: (json['tags'] as List)
|
||||||
|
.map((item) => TagModel.fromJson(item))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'createdAt': createdAt.toIso8601String(),
|
||||||
|
'updatedAt': updatedAt.toIso8601String(),
|
||||||
|
'modelName': modelName,
|
||||||
|
'disabled': disabled,
|
||||||
|
'subspaceModels': subspaceModels.map((e) => e.toJson()).toList(),
|
||||||
|
'tags': tags.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubspaceModel {
|
||||||
|
final String uuid;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final String subspaceName;
|
||||||
|
final bool disabled;
|
||||||
|
final List<TagModel> tags;
|
||||||
|
|
||||||
|
SubspaceModel({
|
||||||
|
required this.uuid,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.subspaceName,
|
||||||
|
required this.disabled,
|
||||||
|
required this.tags,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory SubspaceModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return SubspaceModel(
|
||||||
|
uuid: json['uuid'] ?? '',
|
||||||
|
createdAt: DateTime.parse(json['createdAt']),
|
||||||
|
updatedAt: DateTime.parse(json['updatedAt']),
|
||||||
|
subspaceName: json['subspaceName'] ?? '',
|
||||||
|
disabled: json['disabled'] ?? false,
|
||||||
|
tags: (json['tags'] as List)
|
||||||
|
.map((item) => TagModel.fromJson(item))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'createdAt': createdAt.toIso8601String(),
|
||||||
|
'updatedAt': updatedAt.toIso8601String(),
|
||||||
|
'subspaceName': subspaceName,
|
||||||
|
'disabled': disabled,
|
||||||
|
'tags': tags.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TagModel {
|
||||||
|
final String uuid;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final String tag;
|
||||||
|
final bool disabled;
|
||||||
|
final ProductModel? product;
|
||||||
|
|
||||||
|
TagModel({
|
||||||
|
required this.uuid,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.tag,
|
||||||
|
required this.disabled,
|
||||||
|
this.product,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory TagModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return TagModel(
|
||||||
|
uuid: json['uuid'] ?? '',
|
||||||
|
createdAt: DateTime.parse(json['createdAt']),
|
||||||
|
updatedAt: DateTime.parse(json['updatedAt']),
|
||||||
|
tag: json['tag'] ?? '',
|
||||||
|
disabled: json['disabled'] ?? false,
|
||||||
|
product: json['product'] != null
|
||||||
|
? ProductModel.fromMap(json['product'])
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'createdAt': createdAt.toIso8601String(),
|
||||||
|
'updatedAt': updatedAt.toIso8601String(),
|
||||||
|
'tag': tag,
|
||||||
|
'disabled': disabled,
|
||||||
|
'product': product?.toMap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/space_model_card_widget.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class SpaceModelPage extends StatelessWidget {
|
||||||
|
final List<SpaceTemplateModel> spaceModels;
|
||||||
|
|
||||||
|
const SpaceModelPage({Key? key, required this.spaceModels}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(20.0, 16.0, 16.0, 16.0),
|
||||||
|
child: GridView.builder(
|
||||||
|
//clipBehavior: Clip.none,
|
||||||
|
shrinkWrap: false,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 3,
|
||||||
|
crossAxisSpacing: 14.0,
|
||||||
|
mainAxisSpacing: 14.0,
|
||||||
|
childAspectRatio: 3,
|
||||||
|
),
|
||||||
|
itemCount: spaceModels.length + 1,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == spaceModels.length) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: ColorsManager.semiTransparentBlackColor,
|
||||||
|
blurRadius: 15,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
spreadRadius: 0,
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: ColorsManager.semiTransparentBlackColor,
|
||||||
|
blurRadius: 25,
|
||||||
|
offset: Offset(0, 15),
|
||||||
|
spreadRadius: -5,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
width: 60,
|
||||||
|
height: 60,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: ColorsManager.neutralGray,
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.textFieldGreyColor,
|
||||||
|
width: 2.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.add,
|
||||||
|
size: 40,
|
||||||
|
color: ColorsManager.spaceColor, // Icon color
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final model = spaceModels[index];
|
||||||
|
return SpaceModelCardWidget(model: model);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_chip_widget.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class SpaceModelCardWidget extends StatelessWidget {
|
||||||
|
final SpaceTemplateModel model;
|
||||||
|
|
||||||
|
const SpaceModelCardWidget({Key? key, required this.model}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final Map<String, int> productTagCount = {};
|
||||||
|
|
||||||
|
for (var tag in model.tags) {
|
||||||
|
final prodIcon = tag.product?.icon ?? 'Unknown';
|
||||||
|
productTagCount[prodIcon] = (productTagCount[prodIcon] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var subspace in model.subspaceModels) {
|
||||||
|
for (var tag in subspace.tags) {
|
||||||
|
final prodIcon = tag.product?.icon ?? 'Unknown';
|
||||||
|
productTagCount[prodIcon] = (productTagCount[prodIcon] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.5),
|
||||||
|
spreadRadius: 2,
|
||||||
|
blurRadius: 5,
|
||||||
|
offset: const Offset(0, 3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.fromLTRB(16.0, 14.0, 8.0, 8.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
model.modelName,
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 3.0,
|
||||||
|
runSpacing: 3.0,
|
||||||
|
children: [
|
||||||
|
for (var subspace in model.subspaceModels.take(3))
|
||||||
|
SubspaceChipWidget(subspace: subspace.subspaceName),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (productTagCount.isNotEmpty)
|
||||||
|
Container(
|
||||||
|
width: 1,
|
||||||
|
height: double.infinity,
|
||||||
|
color: ColorsManager.softGray,
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 7),
|
||||||
|
Expanded(
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 4.0,
|
||||||
|
runSpacing: 4.0,
|
||||||
|
children: productTagCount.entries.map((entry) {
|
||||||
|
final prodType = entry.key;
|
||||||
|
final count = entry.value;
|
||||||
|
|
||||||
|
return Chip(
|
||||||
|
label: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
prodType,
|
||||||
|
width: 15,
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(
|
||||||
|
'x$count', // Product count
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
backgroundColor: ColorsManager.textFieldGreyColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: const BorderSide(
|
||||||
|
color: ColorsManager.transparentColor,
|
||||||
|
width: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class SubspaceChipWidget extends StatelessWidget {
|
||||||
|
final String subspace;
|
||||||
|
|
||||||
|
const SubspaceChipWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.subspace,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Chip(
|
||||||
|
label: Text(
|
||||||
|
subspace,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
),
|
||||||
|
backgroundColor: ColorsManager.textFieldGreyColor,
|
||||||
|
labelStyle: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall
|
||||||
|
?.copyWith(color: ColorsManager.spaceColor),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: const BorderSide(
|
||||||
|
color: Colors.transparent,
|
||||||
|
width: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,10 @@ class CenterBodyWidget extends StatelessWidget {
|
|||||||
context.read<SpaceManagementBloc>().add(BlankStateEvent());
|
context.read<SpaceManagementBloc>().add(BlankStateEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state is SpaceModelState) {
|
||||||
|
context.read<SpaceManagementBloc>().add(SpaceModelLoadEvent());
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
37
lib/services/space_model_mang_api.dart
Normal file
37
lib/services/space_model_mang_api.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||||
|
|
||||||
|
class SpaceModelManagementApi {
|
||||||
|
Future<List<SpaceTemplateModel>> listSpaceModels({int page = 1}) async {
|
||||||
|
try {
|
||||||
|
List<SpaceTemplateModel> spaceModels = [];
|
||||||
|
bool hasNext = true;
|
||||||
|
while (hasNext) {
|
||||||
|
await HTTPService().get(
|
||||||
|
path: ApiEndpoints.listSpaceModels
|
||||||
|
.replaceAll('{projectId}', TempConst.projectId),
|
||||||
|
queryParameters: {'page': page},
|
||||||
|
expectedResponseModel: (json) {
|
||||||
|
List<dynamic> jsonData = json['data'];
|
||||||
|
hasNext = json['hasNext'] ?? false;
|
||||||
|
int currentPage = json['page'] ?? 1;
|
||||||
|
List<SpaceTemplateModel> spaceModelList = jsonData.map((jsonItem) {
|
||||||
|
return SpaceTemplateModel.fromJson(jsonItem);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
spaceModels.addAll(spaceModelList);
|
||||||
|
page = currentPage + 1;
|
||||||
|
return spaceModelList;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return spaceModels;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Error fetching space models: $e');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -54,5 +54,7 @@ abstract class ColorsManager {
|
|||||||
static const Color warningRed = Color(0xFFFF6465);
|
static const Color warningRed = Color(0xFFFF6465);
|
||||||
static const Color borderColor = Color(0xFFE5E5E5);
|
static const Color borderColor = Color(0xFFE5E5E5);
|
||||||
static const Color CircleImageBackground = Color(0xFFF4F4F4);
|
static const Color CircleImageBackground = Color(0xFFF4F4F4);
|
||||||
|
static const Color softGray = Color(0xFFD5D5D5);
|
||||||
|
static const Color semiTransparentBlack = Color(0x19000000)
|
||||||
}
|
}
|
||||||
//background: #background: #5D5D5D;
|
//background: #background: #5D5D5D;
|
||||||
|
@ -11,12 +11,14 @@ abstract class ApiEndpoints {
|
|||||||
static const String visitorPassword = '/visitor-password';
|
static const String visitorPassword = '/visitor-password';
|
||||||
static const String getDevices = '/visitor-password/devices';
|
static const String getDevices = '/visitor-password/devices';
|
||||||
|
|
||||||
static const String sendOnlineOneTime = '/visitor-password/temporary-password/online/one-time';
|
static const String sendOnlineOneTime =
|
||||||
|
'/visitor-password/temporary-password/online/one-time';
|
||||||
static const String sendOnlineMultipleTime =
|
static const String sendOnlineMultipleTime =
|
||||||
'/visitor-password/temporary-password/online/multiple-time';
|
'/visitor-password/temporary-password/online/multiple-time';
|
||||||
|
|
||||||
//offline Password
|
//offline Password
|
||||||
static const String sendOffLineOneTime = '/visitor-password/temporary-password/offline/one-time';
|
static const String sendOffLineOneTime =
|
||||||
|
'/visitor-password/temporary-password/offline/one-time';
|
||||||
static const String sendOffLineMultipleTime =
|
static const String sendOffLineMultipleTime =
|
||||||
'/visitor-password/temporary-password/offline/multiple-time';
|
'/visitor-password/temporary-password/offline/multiple-time';
|
||||||
|
|
||||||
@ -36,30 +38,45 @@ abstract class ApiEndpoints {
|
|||||||
static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}';
|
static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}';
|
||||||
|
|
||||||
// Space Module
|
// Space Module
|
||||||
static const String createSpace = '/projects/{projectId}/communities/{communityId}/spaces';
|
static const String createSpace =
|
||||||
static const String listSpaces = '/projects/{projectId}/communities/{communityId}/spaces';
|
'/projects/{projectId}/communities/{communityId}/spaces';
|
||||||
static const String deleteSpace = '/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
|
static const String listSpaces =
|
||||||
static const String updateSpace = '/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
|
'/projects/{projectId}/communities/{communityId}/spaces';
|
||||||
static const String getSpace = '/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
|
static const String deleteSpace =
|
||||||
static const String getSpaceHierarchy = '/projects/{projectId}/communities/{communityId}/spaces';
|
'/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
|
||||||
|
static const String updateSpace =
|
||||||
|
'/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
|
||||||
|
static const String getSpace =
|
||||||
|
'/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
|
||||||
|
static const String getSpaceHierarchy =
|
||||||
|
'/projects/{projectId}/communities/{communityId}/spaces';
|
||||||
|
|
||||||
// Community Module
|
// Community Module
|
||||||
static const String createCommunity = '/projects/{projectId}/communities';
|
static const String createCommunity = '/projects/{projectId}/communities';
|
||||||
static const String getCommunityList = '/projects/{projectId}/communities';
|
static const String getCommunityList = '/projects/{projectId}/communities';
|
||||||
static const String getCommunityById = '/projects/{projectId}/communities/{communityId}';
|
static const String getCommunityById =
|
||||||
static const String updateCommunity = '/projects/{projectId}/communities/{communityId}';
|
'/projects/{projectId}/communities/{communityId}';
|
||||||
static const String deleteCommunity = '/projects/{projectId}communities/{communityId}';
|
static const String updateCommunity =
|
||||||
static const String getUserCommunities = '/projects/{projectId}/communities/user/{userUuid}';
|
'/projects/{projectId}/communities/{communityId}';
|
||||||
static const String createUserCommunity = '/projects/{projectId}/communities/user';
|
static const String deleteCommunity =
|
||||||
|
'/projects/{projectId}communities/{communityId}';
|
||||||
|
static const String getUserCommunities =
|
||||||
|
'/projects/{projectId}/communities/user/{userUuid}';
|
||||||
|
static const String createUserCommunity =
|
||||||
|
'/projects/{projectId}/communities/user';
|
||||||
static const String getDeviceLogsByDate =
|
static const String getDeviceLogsByDate =
|
||||||
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
|
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
|
||||||
|
|
||||||
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
|
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
|
||||||
static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}';
|
static const String getScheduleByDeviceId =
|
||||||
static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}';
|
'/schedule/{deviceUuid}?category={category}';
|
||||||
static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}';
|
static const String deleteScheduleByDeviceId =
|
||||||
|
'/schedule/{deviceUuid}/{scheduleUuid}';
|
||||||
|
static const String updateScheduleByDeviceId =
|
||||||
|
'/schedule/enable/{deviceUuid}';
|
||||||
static const String factoryReset = '/device/factory/reset/{deviceUuid}';
|
static const String factoryReset = '/device/factory/reset/{deviceUuid}';
|
||||||
static const String powerClamp = '/device/{powerClampUuid}/power-clamp/status';
|
static const String powerClamp =
|
||||||
|
'/device/{powerClampUuid}/power-clamp/status';
|
||||||
|
|
||||||
//product
|
//product
|
||||||
static const String listProducts = '/products';
|
static const String listProducts = '/products';
|
||||||
@ -68,13 +85,18 @@ abstract class ApiEndpoints {
|
|||||||
static const String getIconScene = '/scene/icon';
|
static const String getIconScene = '/scene/icon';
|
||||||
static const String createScene = '/scene/tap-to-run';
|
static const String createScene = '/scene/tap-to-run';
|
||||||
static const String createAutomation = '/automation';
|
static const String createAutomation = '/automation';
|
||||||
static const String getUnitScenes = '/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/scenes';
|
static const String getUnitScenes =
|
||||||
static const String getAutomationDetails = '/automation/details/{automationId}';
|
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/scenes';
|
||||||
|
static const String getAutomationDetails =
|
||||||
|
'/automation/details/{automationId}';
|
||||||
static const String getScene = '/scene/tap-to-run/{sceneId}';
|
static const String getScene = '/scene/tap-to-run/{sceneId}';
|
||||||
static const String deleteScene = '/scene/tap-to-run/{sceneId}';
|
static const String deleteScene = '/scene/tap-to-run/{sceneId}';
|
||||||
|
|
||||||
static const String deleteAutomation = '/automation/{automationId}';
|
static const String deleteAutomation = '/automation/{automationId}';
|
||||||
static const String updateScene = '/scene/tap-to-run/{sceneId}';
|
static const String updateScene = '/scene/tap-to-run/{sceneId}';
|
||||||
|
|
||||||
static const String updateAutomation = '/automation/{automationId}';
|
static const String updateAutomation = '/automation/{automationId}';
|
||||||
|
|
||||||
|
//space model
|
||||||
|
static const String listSpaceModels = '/projects/{projectId}/space-models';
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user