push routine details model and api settup

This commit is contained in:
ashrafzarkanisala
2024-11-27 21:03:19 +03:00
parent cf817fd5dc
commit 9b5ddc4dc8
8 changed files with 499 additions and 188 deletions

View File

@ -13,7 +13,7 @@ part 'routine_event.dart';
part 'routine_state.dart';
const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
const communityId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
const communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
RoutineBloc() : super(const RoutineState()) {

View File

@ -0,0 +1,262 @@
import 'dart:convert';
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart';
class RoutineDetailsModel {
final String spaceUuid;
final String name;
final String decisionExpr;
final List<RoutineAction> actions;
final String? iconId;
final bool? showInDevice;
final EffectiveTime? effectiveTime;
final List<RoutineCondition>? conditions;
final String? type;
RoutineDetailsModel({
required this.spaceUuid,
required this.name,
required this.decisionExpr,
required this.actions,
this.iconId,
this.showInDevice,
this.effectiveTime,
this.conditions,
this.type,
});
// Convert to CreateSceneModel
CreateSceneModel toCreateSceneModel() {
return CreateSceneModel(
spaceUuid: spaceUuid,
iconId: iconId ?? '',
showInDevice: showInDevice ?? false,
sceneName: name,
decisionExpr: decisionExpr,
actions: actions.map((a) => a.toCreateSceneAction()).toList(),
);
}
// Convert to CreateAutomationModel
CreateAutomationModel toCreateAutomationModel() {
return CreateAutomationModel(
spaceUuid: spaceUuid,
automationName: name,
decisionExpr: decisionExpr,
effectiveTime:
effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
conditions: conditions?.map((c) => c.toCondition()).toList() ?? [],
actions: actions.map((a) => a.toAutomationAction()).toList(),
);
}
Map<String, dynamic> toMap() {
return {
'spaceUuid': spaceUuid,
'name': name,
'decisionExpr': decisionExpr,
'actions': actions.map((x) => x.toMap()).toList(),
if (iconId != null) 'iconId': iconId,
if (showInDevice != null) 'showInDevice': showInDevice,
if (effectiveTime != null) 'effectiveTime': effectiveTime!.toMap(),
if (conditions != null)
'conditions': conditions!.map((x) => x.toMap()).toList(),
if (type != null) 'type': type,
};
}
factory RoutineDetailsModel.fromMap(Map<String, dynamic> map) {
return RoutineDetailsModel(
spaceUuid: map['spaceUuid'] ?? '',
name: map['name'] ?? '',
decisionExpr: map['decisionExpr'] ?? '',
actions: List<RoutineAction>.from(
map['actions']?.map((x) => RoutineAction.fromMap(x)) ?? [],
),
iconId: map['iconId'],
showInDevice: map['showInDevice'],
effectiveTime: map['effectiveTime'] != null
? EffectiveTime.fromMap(map['effectiveTime'])
: null,
conditions: map['conditions'] != null
? List<RoutineCondition>.from(
map['conditions'].map((x) => RoutineCondition.fromMap(x)))
: null,
type: map['type'],
);
}
String toJson() => json.encode(toMap());
factory RoutineDetailsModel.fromJson(String source) =>
RoutineDetailsModel.fromMap(json.decode(source));
}
class RoutineAction {
final String entityId;
final String actionExecutor;
final RoutineExecutorProperty? executorProperty;
RoutineAction({
required this.entityId,
required this.actionExecutor,
this.executorProperty,
});
CreateSceneAction toCreateSceneAction() {
return CreateSceneAction(
entityId: entityId,
actionExecutor: actionExecutor,
executorProperty: executorProperty?.toCreateSceneExecutorProperty(),
);
}
AutomationAction toAutomationAction() {
return AutomationAction(
entityId: entityId,
actionExecutor: actionExecutor,
executorProperty: executorProperty?.toExecutorProperty(),
);
}
Map<String, dynamic> toMap() {
return {
'entityId': entityId,
'actionExecutor': actionExecutor,
if (executorProperty != null)
'executorProperty': executorProperty!.toMap(),
};
}
factory RoutineAction.fromMap(Map<String, dynamic> map) {
return RoutineAction(
entityId: map['entityId'] ?? '',
actionExecutor: map['actionExecutor'] ?? '',
executorProperty: map['executorProperty'] != null
? RoutineExecutorProperty.fromMap(map['executorProperty'])
: null,
);
}
}
class RoutineExecutorProperty {
final String? functionCode;
final dynamic functionValue;
final int? delaySeconds;
RoutineExecutorProperty({
this.functionCode,
this.functionValue,
this.delaySeconds,
});
CreateSceneExecutorProperty toCreateSceneExecutorProperty() {
return CreateSceneExecutorProperty(
functionCode: functionCode ?? '',
functionValue: functionValue,
delaySeconds: delaySeconds ?? 0,
);
}
ExecutorProperty toExecutorProperty() {
return ExecutorProperty(
functionCode: functionCode,
functionValue: functionValue,
delaySeconds: delaySeconds,
);
}
Map<String, dynamic> toMap() {
return {
if (functionCode != null) 'functionCode': functionCode,
if (functionValue != null) 'functionValue': functionValue,
if (delaySeconds != null) 'delaySeconds': delaySeconds,
};
}
factory RoutineExecutorProperty.fromMap(Map<String, dynamic> map) {
return RoutineExecutorProperty(
functionCode: map['functionCode'],
functionValue: map['functionValue'],
delaySeconds: map['delaySeconds']?.toInt(),
);
}
}
class RoutineCondition {
final int code;
final String entityId;
final String entityType;
final RoutineConditionExpr expr;
RoutineCondition({
required this.code,
required this.entityId,
required this.entityType,
required this.expr,
});
Condition toCondition() {
return Condition(
code: code,
entityId: entityId,
entityType: entityType,
expr: expr.toConditionExpr(),
);
}
Map<String, dynamic> toMap() {
return {
'code': code,
'entityId': entityId,
'entityType': entityType,
'expr': expr.toMap(),
};
}
factory RoutineCondition.fromMap(Map<String, dynamic> map) {
return RoutineCondition(
code: map['code']?.toInt() ?? 0,
entityId: map['entityId'] ?? '',
entityType: map['entityType'] ?? '',
expr: RoutineConditionExpr.fromMap(map['expr']),
);
}
}
class RoutineConditionExpr {
final String statusCode;
final String comparator;
final dynamic statusValue;
RoutineConditionExpr({
required this.statusCode,
required this.comparator,
required this.statusValue,
});
ConditionExpr toConditionExpr() {
return ConditionExpr(
statusCode: statusCode,
comparator: comparator,
statusValue: statusValue,
);
}
Map<String, dynamic> toMap() {
return {
'statusCode': statusCode,
'comparator': comparator,
'statusValue': statusValue,
};
}
factory RoutineConditionExpr.fromMap(Map<String, dynamic> map) {
return RoutineConditionExpr(
statusCode: map['statusCode'] ?? '',
comparator: map['comparator'] ?? '',
statusValue: map['statusValue'],
);
}
}

View File

@ -1,7 +1,10 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:syncrow_web/utils/constants/assets.dart';
class ScenesModel {
final String id;
final String? sceneTuyaId;
final String name;
final String status;
final String type;
@ -9,26 +12,36 @@ class ScenesModel {
ScenesModel({
required this.id,
this.sceneTuyaId,
required this.name,
required this.status,
required this.type,
this.icon,
});
factory ScenesModel.fromRawJson(String str) =>
ScenesModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
Uint8List get iconInBytes => base64Decode(icon ?? '');
factory ScenesModel.fromJson(Map<String, dynamic> json,
{bool? isAutomation}) =>
ScenesModel(
id: json["id"],
{bool? isAutomation}) {
return ScenesModel(
id: json["id"] ?? json["uuid"] ?? '',
sceneTuyaId: json["sceneTuyaId"] as String?,
name: json["name"] ?? '',
status: json["status"] ?? '',
type: json["type"] ?? '',
icon: isAutomation == true
? Assets.automation
: (json["icon"] as String?),
icon:
isAutomation == true ? Assets.automation : (json["icon"] as String?),
);
}
Map<String, dynamic> toJson() => {
"id": id,
"sceneTuyaId": sceneTuyaId ?? '',
"name": name,
"status": status,
"type": type,

View File

@ -47,7 +47,7 @@ class RoutinesView extends StatelessWidget {
textString: '',
),
const SizedBox(
height: 30,
height: 15,
),
const Expanded(child: FetchRoutineScenesAutomation()),
],

View File

@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_vie
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';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class FetchRoutineScenesAutomation extends StatefulWidget {
const FetchRoutineScenesAutomation({super.key});
@ -14,7 +15,8 @@ class FetchRoutineScenesAutomation extends StatefulWidget {
_FetchRoutineScenesState();
}
class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation> {
class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
with HelperResponsiveLayout {
@override
void initState() {
super.initState();
@ -27,10 +29,12 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation> {
Widget build(BuildContext context) {
return BlocBuilder<RoutineBloc, RoutineState>(
builder: (context, state) {
return SizedBox(
height: 500,
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (state.isLoading)
const Center(
@ -52,22 +56,29 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation> {
),
),
if (state.scenes.isNotEmpty)
SizedBox(
height: 200,
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isSmallScreenSize(context) ? 160 : 170,
),
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: state.scenes.length,
itemBuilder: (context, index) {
return RoutineViewCard(
itemBuilder: (context, index) => Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: RoutineViewCard(
onTap: () {},
textString: state.scenes[index].name,
icon: state.scenes[index].icon ?? Assets.logoHorizontal,
);
},
icon:
state.scenes[index].icon ?? Assets.logoHorizontal,
isFromScenes: true,
iconInBytes: state.scenes[index].iconInBytes,
),
),
const SizedBox(height: 30),
),
),
const SizedBox(height: 15),
Text(
"Automations",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
@ -84,27 +95,29 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation> {
),
),
if (state.automations.isNotEmpty)
SizedBox(
height: 200,
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isSmallScreenSize(context) ? 160 : 170,
),
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: state.automations.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(right: 8.0),
itemBuilder: (context, index) => Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: RoutineViewCard(
onTap: () {},
textString: state.automations[index].name,
icon: state.automations[index].icon ??
Assets.automation,
),
);
},
),
),
),
],
),
),
);
},
);

View File

@ -1,39 +1,61 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_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';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class RoutineViewCard extends StatelessWidget {
class RoutineViewCard extends StatelessWidget with HelperResponsiveLayout {
const RoutineViewCard({
super.key,
required this.onTap,
required this.icon,
required this.textString,
this.isFromScenes,
this.iconInBytes,
});
final Function() onTap;
final dynamic icon;
final String textString;
final bool? isFromScenes;
final Uint8List? iconInBytes;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 200,
width: 150,
child: GestureDetector(
onTap: () {
onTap();
},
final double cardWidth = isSmallScreenSize(context)
? 120
: isMediumScreenSize(context)
? 135
: 150;
final double cardHeight = isSmallScreenSize(context) ? 160 : 170;
final double iconSize = isSmallScreenSize(context)
? 50
: isMediumScreenSize(context)
? 60
: 70;
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: cardWidth,
maxHeight: cardHeight,
),
child: Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
color: ColorsManager.whiteColors,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(10),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Container(
@ -45,22 +67,39 @@ class RoutineViewCard extends StatelessWidget {
width: 2.0,
),
),
height: 70,
width: 70,
child: (icon is String)
? icon.endsWith('.svg')
? SvgPicture.asset(
icon,
height: iconSize,
width: iconSize,
child: (isFromScenes ?? false)
? (iconInBytes != null &&
iconInBytes?.isNotEmpty == true)
? Image.memory(
iconInBytes!,
height: iconSize,
width: iconSize,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) =>
Image.asset(
Assets.logo,
height: iconSize,
width: iconSize,
fit: BoxFit.contain,
),
)
: Image.asset(
Assets.logo,
height: iconSize,
width: iconSize,
fit: BoxFit.contain,
)
: (icon is String && icon.endsWith('.svg'))
? SvgPicture.asset(
icon,
fit: BoxFit.contain,
)
: Icon(
icon,
color: ColorsManager.dialogBlueTitle,
size: 40,
size: isSmallScreenSize(context) ? 30 : 40,
),
),
),
@ -74,7 +113,7 @@ class RoutineViewCard extends StatelessWidget {
maxLines: 2,
style: context.textTheme.bodySmall?.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontSize: isSmallScreenSize(context) ? 10 : 12,
),
),
),
@ -82,6 +121,7 @@ class RoutineViewCard extends StatelessWidget {
),
),
),
),
);
}
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart';
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
import 'package:syncrow_web/pages/routiens/models/routine_details_model.dart';
import 'package:syncrow_web/pages/routiens/models/routine_model.dart';
import 'package:syncrow_web/services/api/http_service.dart';
import 'package:syncrow_web/utils/constants/api_const.dart';
@ -67,7 +68,7 @@ class SceneApi {
return response;
}
//get scene by unit id
//get scenes by community id and space id
static Future<List<ScenesModel>> getScenesByUnitId(
String unitId, String communityId,
@ -95,25 +96,6 @@ class SceneApi {
}
}
// static Future<List<ScenesModel>> getScenesByUnitId(String unitId) async {
// try {
// final response = await _httpService.get(
// path: ApiEndpoints.getSpaceScenes.replaceAll('{unitUuid}', unitId),
// showServerMessage: false,
// expectedResponseModel: (json) {
// List<ScenesModel> scenes = [];
// for (var scene in json) {
// scenes.add(ScenesModel.fromJson(scene));
// }
// return scenes;
// },
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//getAutomation
static Future<List<ScenesModel>> getAutomationByUnitId(String unitId) async {
@ -148,21 +130,21 @@ class SceneApi {
// }
// }
// //automation details
// static Future<SceneDetailsModel> getAutomationDetails(
// String automationId) async {
// try {
// final response = await _httpService.get(
// path: ApiEndpoints.getAutomationDetails
// .replaceAll('{automationId}', automationId),
// showServerMessage: false,
// expectedResponseModel: (json) => SceneDetailsModel.fromJson(json),
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//automation details
static Future<RoutineDetailsModel> getAutomationDetails(
String automationId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getAutomationDetails
.replaceAll('{automationId}', automationId),
showServerMessage: false,
expectedResponseModel: (json) => RoutineDetailsModel.fromJson(json),
);
return response;
} catch (e) {
rethrow;
}
}
//
// //updateAutomationStatus
// static Future<bool> updateAutomationStatus(String automationId,
@ -180,20 +162,19 @@ class SceneApi {
// }
// }
// //getScene
//
// static Future<SceneDetailsModel> getSceneDetails(String sceneId) async {
// try {
// final response = await _httpService.get(
// path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId),
// showServerMessage: false,
// expectedResponseModel: (json) => SceneDetailsModel.fromJson(json),
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//getScene
static Future<RoutineDetailsModel> getSceneDetails(String sceneId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId),
showServerMessage: false,
expectedResponseModel: (json) => RoutineDetailsModel.fromJson(json),
);
return response;
} catch (e) {
rethrow;
}
}
//
// //update Scene
// static updateScene(CreateSceneModel createSceneModel, String sceneId) async {

View File

@ -46,7 +46,6 @@ abstract class ApiEndpoints {
'/schedule/{deviceUuid}/{scheduleUuid}';
static const String updateScheduleByDeviceId =
'/schedule/enable/{deviceUuid}';
static const String factoryReset = '/device/factory/reset/{deviceUuid}';
static const String powerClamp =
'/device/{powerClampUuid}/power-clamp/status';
@ -57,4 +56,7 @@ abstract class ApiEndpoints {
static const String createAutomation = '/automation';
static const String getUnitScenes =
'/communities/{communityUuid}/spaces/{spaceUuid}/scenes';
static const String getAutomationDetails =
'/automation/details/{automationId}';
static const String getScene = '/scene/tap-to-run/{sceneId}';
}