mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-17 02:25:16 +00:00
Compare commits
29 Commits
feat/updat
...
fix-device
Author | SHA1 | Date | |
---|---|---|---|
2b0e504f05 | |||
a656d5981e | |||
3f49a18130 | |||
a51c4d9679 | |||
caeed8e73f | |||
dc5ac9be5b | |||
5c9b30895f | |||
06b14a3964 | |||
3c92ea3047 | |||
73d28a1800 | |||
5493ca6fb0 | |||
7005d8ba83 | |||
cb79627038 | |||
1cff69d496 | |||
60df77efad | |||
9e84048f81 | |||
99adb1c286 | |||
f2412aa867 | |||
e4768c95aa | |||
f25b4dbf6d | |||
9eff9ab371 | |||
a2e68d6194 | |||
94c94b170f | |||
253cf15559 | |||
443eea9421 | |||
87a2c08f64 | |||
dd66e7c747 | |||
7af61d2f65 | |||
f37eacb0ee |
2
.env.dev
2
.env.dev
@ -1,3 +1,5 @@
|
||||
ENV_NAME=development
|
||||
BASE_URL=https://syncrow-dev.azurewebsites.net
|
||||
PROJECT_ID=0e62577c-06fa-41b9-8a92-99a21fbaf51c
|
||||
CLIENT_ID=c024573d191a327ce74db7d4502fdc29
|
||||
CLIENT_SECRET=fec6ccbc33664f94a3b84a45c7cceef3f3ebd1613ef4307db8946ede530cd1ed
|
10
assets/icons/cancel_icon.svg
Normal file
10
assets/icons/cancel_icon.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_7302_4118)">
|
||||
<path d="M11.1049 10.0001L19.7712 1.33381C20.0763 1.02869 20.0763 0.534007 19.7712 0.228929C19.4661 -0.0761485 18.9714 -0.0761876 18.6663 0.228929L9.99999 8.89524L1.33372 0.228929C1.0286 -0.0761876 0.533915 -0.0761876 0.228837 0.228929C-0.0762401 0.534046 -0.0762792 1.02873 0.228837 1.33381L8.89511 10.0001L0.228837 18.6664C-0.0762792 18.9715 -0.0762792 19.4662 0.228837 19.7713C0.381376 19.9238 0.581337 20.0001 0.781297 20.0001C0.981258 20.0001 1.18118 19.9238 1.33376 19.7713L9.99999 11.105L18.6663 19.7713C18.8188 19.9238 19.0188 20.0001 19.2187 20.0001C19.4187 20.0001 19.6186 19.9238 19.7712 19.7713C20.0763 19.4662 20.0763 18.9715 19.7712 18.6664L11.1049 10.0001Z" fill="#999999"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7302_4118">
|
||||
<rect width="20" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 939 B |
10
assets/icons/save_routines_icon.svg
Normal file
10
assets/icons/save_routines_icon.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_7302_4149)">
|
||||
<path d="M19.9969 4.94279C19.986 4.83232 19.943 4.72146 19.8674 4.62924C19.8382 4.59358 20.1367 4.89431 15.4141 0.17176C15.3015 0.0591838 15.1487 8.30277e-05 14.9996 0.00012209C14.6443 0.00012209 2.11177 0.00012209 1.75779 0.00012209C0.788544 0.00012209 0 0.788666 0 1.75791V18.2421C0 19.2113 0.788544 19.9998 1.75779 19.9998H18.2419C19.2112 19.9998 19.9997 19.2113 19.9997 18.2421C19.9998 4.01624 20.0013 4.98771 19.9969 4.94279ZM13.4764 1.17198V5.00005C13.4764 5.32314 13.2136 5.58598 12.8905 5.58598H12.1483V1.17198H13.4764ZM10.9765 1.17198V5.58598H5.54684C5.22376 5.58598 4.96091 5.32314 4.96091 5.00005V1.17198H10.9765ZM13.4764 12.539H4.96091V11.7968C4.96091 11.4738 5.22376 11.2109 5.54684 11.2109H12.8905C13.2136 11.2109 13.4764 11.4738 13.4764 11.7968V12.539ZM4.96091 18.828V13.7109H13.4764V18.828H4.96091ZM18.8279 18.2421C18.8279 18.5651 18.5651 18.828 18.242 18.828H14.6483C14.6483 18.0641 14.6483 12.6676 14.6483 11.7968C14.6483 10.8276 13.8597 10.039 12.8905 10.039H5.54684C4.57759 10.039 3.78905 10.8276 3.78905 11.7968V18.828H1.75783C1.43475 18.828 1.1719 18.5651 1.1719 18.2421V1.75791C1.1719 1.43483 1.43475 1.17198 1.75783 1.17198H3.78905V5.00005C3.78905 5.9693 4.57759 6.75784 5.54684 6.75784H12.8905C13.8597 6.75784 14.6483 5.9693 14.6483 5.00005V1.17198H14.7571L18.8279 5.24278V18.2421Z" fill="#023DFE" fill-opacity="0.6"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7302_4149">
|
||||
<rect width="20" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:syncrow_app/features/auth/model/login_with_email_model.dart';
|
||||
import 'package:syncrow_app/features/auth/model/signup_model.dart';
|
||||
@ -217,9 +218,22 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
signUp() async {
|
||||
emit(AuthLoginLoading());
|
||||
final response;
|
||||
|
||||
final clientId = dotenv.env['CLIENT_ID'] ?? '';
|
||||
final clientSecret = dotenv.env['CLIENT_SECRET'] ?? '';
|
||||
|
||||
try {
|
||||
List<String> userFullName = fullName.split(' ');
|
||||
|
||||
final clientToken = await AuthenticationAPI.fetchClientToken(
|
||||
clientId: clientId,
|
||||
clientSecret: clientSecret,
|
||||
);
|
||||
|
||||
final accessToken = clientToken['accessToken'];
|
||||
|
||||
response = await AuthenticationAPI.signUp(
|
||||
accessToken: accessToken,
|
||||
model: SignUpModel(
|
||||
hasAcceptedAppAgreement: true,
|
||||
email: email.toLowerCase(),
|
||||
|
@ -169,18 +169,20 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
|
||||
}
|
||||
}
|
||||
|
||||
_getOnlyImplementedDevices(List<DeviceModel> devices) {
|
||||
List<DeviceModel> implementedDevices = [];
|
||||
for (int i = 0; i < devices.length; i++) {
|
||||
if (devices[i].productType == DeviceType.AC ||
|
||||
devices[i].productType == DeviceType.DoorLock ||
|
||||
devices[i].productType == DeviceType.Gateway ||
|
||||
devices[i].productType == DeviceType.WallSensor ||
|
||||
devices[i].productType == DeviceType.CeilingSensor ||
|
||||
devices[i].productType == DeviceType.ThreeGang) {
|
||||
implementedDevices.add(devices[i]);
|
||||
}
|
||||
}
|
||||
return implementedDevices;
|
||||
List<DeviceModel> _getOnlyImplementedDevices(List<DeviceModel> devices) {
|
||||
const allowedDeviceTypes = {
|
||||
DeviceType.AC,
|
||||
DeviceType.DoorLock,
|
||||
DeviceType.Gateway,
|
||||
DeviceType.WallSensor,
|
||||
DeviceType.CeilingSensor,
|
||||
DeviceType.ThreeGang,
|
||||
DeviceType.OneGang,
|
||||
DeviceType.TwoGang
|
||||
};
|
||||
|
||||
return devices
|
||||
.where((device) => allowedDeviceTypes.contains(device.productType))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
@ -76,32 +76,45 @@ class RoomPageSwitch extends StatelessWidget {
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
Flexible(
|
||||
child: FittedBox(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
device.name ?? "",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
style: context.bodyLarge.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
color: Colors.grey,
|
||||
),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final text = device.name ?? "";
|
||||
final textPainter = TextPainter(
|
||||
text: TextSpan(
|
||||
text: text,
|
||||
style: context.bodyLarge.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
color: Colors.grey,
|
||||
),
|
||||
Text(
|
||||
device.subspace!.subspaceName ?? '',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: context.bodySmall.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 10,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
maxLines: 1,
|
||||
textDirection: TextDirection.ltr,
|
||||
);
|
||||
|
||||
textPainter.layout(maxWidth: constraints.maxWidth);
|
||||
|
||||
final exceeded = textPainter.didExceedMaxLines;
|
||||
|
||||
return Text(
|
||||
exceeded ? '${text.substring(0, 10)}...' : text,
|
||||
style: context.bodyLarge.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
color: Colors.grey,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
maxLines: 1,
|
||||
);
|
||||
},
|
||||
),
|
||||
Text(
|
||||
device.subspace!.subspaceName ?? '',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: context.bodySmall.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 10,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -119,7 +132,6 @@ Future<void> showDeviceInterface(
|
||||
required BuildContext context,
|
||||
required isAllDevices,
|
||||
List<DeviceModel>? allDevices}) async {
|
||||
print('object-----${device.uuid} ${device.name}');
|
||||
|
||||
final devicesCubit = context.read<DevicesCubit>();
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_event.dart';
|
||||
@ -7,19 +5,31 @@ import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart
|
||||
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_state.dart';
|
||||
|
||||
class TabBarBloc extends Bloc<TabBarEvent, TabBarState> {
|
||||
final DeviceManagerBloc deviceManagerBloc;
|
||||
TabBarBloc(this.deviceManagerBloc) : super(const Initial()) {
|
||||
on<TabChanged>(_handleTabChanged);
|
||||
TabBarBloc(this.deviceManagerBloc) : super(const TabBarInitialState()) {
|
||||
on<TabBarTabChangedEvent>(_onTabBarTabChangedEvent);
|
||||
}
|
||||
|
||||
FutureOr<void> _handleTabChanged(
|
||||
TabChanged event, Emitter<TabBarState> emit) {
|
||||
final DeviceManagerBloc deviceManagerBloc;
|
||||
|
||||
void _onTabBarTabChangedEvent(
|
||||
TabBarTabChangedEvent event,
|
||||
Emitter<TabBarState> emit,
|
||||
) {
|
||||
_getDevices(event);
|
||||
|
||||
emit(
|
||||
TabBarTabSelectedState(
|
||||
roomId: event.roomId,
|
||||
selectedTabIndex: event.selectedIndex,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _getDevices(TabBarTabChangedEvent event) {
|
||||
if (event.roomId == "-1") {
|
||||
deviceManagerBloc.add(FetchAllDevices());
|
||||
} else {
|
||||
deviceManagerBloc.add(FetchDevicesByRoomId(event.roomId,event.unit));
|
||||
deviceManagerBloc.add(FetchDevicesByRoomId(event.roomId, event.unit));
|
||||
}
|
||||
emit(TabSelected(
|
||||
roomId: event.roomId, selectedTabIndex: event.selectedIndex));
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,14 @@ abstract class TabBarEvent {
|
||||
const TabBarEvent();
|
||||
}
|
||||
|
||||
class TabChanged extends TabBarEvent {
|
||||
class TabBarTabChangedEvent extends TabBarEvent {
|
||||
const TabBarTabChangedEvent({
|
||||
required this.selectedIndex,
|
||||
required this.roomId,
|
||||
required this.unit,
|
||||
});
|
||||
|
||||
final int selectedIndex;
|
||||
final String roomId;
|
||||
final SpaceModel unit;
|
||||
const TabChanged(
|
||||
{required this.selectedIndex, required this.roomId, required this.unit});
|
||||
}
|
||||
|
@ -2,12 +2,16 @@ abstract class TabBarState {
|
||||
const TabBarState();
|
||||
}
|
||||
|
||||
class Initial extends TabBarState {
|
||||
const Initial();
|
||||
class TabBarInitialState extends TabBarState {
|
||||
const TabBarInitialState();
|
||||
}
|
||||
|
||||
class TabSelected extends TabBarState {
|
||||
class TabBarTabSelectedState extends TabBarState {
|
||||
const TabBarTabSelectedState({
|
||||
required this.roomId,
|
||||
required this.selectedTabIndex,
|
||||
});
|
||||
|
||||
final int selectedTabIndex;
|
||||
final String roomId;
|
||||
const TabSelected({required this.roomId, required this.selectedTabIndex});
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
|
||||
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
|
||||
class OneGangHelperFunctions {
|
||||
static List<SceneStaticFunction> oneGangHelperFunctions(
|
||||
String deviceId, String deviceName, functionValue) {
|
||||
return [
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'Light Switch',
|
||||
code: 'switch_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'Light CountDown',
|
||||
code: 'countdown_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.countdown,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(icon: '', value: 0),
|
||||
],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
static List<SceneStaticFunction> oneGangAutomationFunctions(
|
||||
String deviceId, String deviceName, functionValue) {
|
||||
return [
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'Light Switch',
|
||||
code: 'switch_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'Light CountDown',
|
||||
code: 'countdown_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.integerSteps,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: '',
|
||||
description: "sec",
|
||||
value: 0.0,
|
||||
minValue: 0,
|
||||
maxValue: 43200,
|
||||
stepValue: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ class ThreeGangHelperFunctions {
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'Light 1 Switch',
|
||||
operationName: 'L - Light Switch',
|
||||
code: 'switch_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
@ -21,11 +21,23 @@ class ThreeGangHelperFunctions {
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'L - Light Countdown',
|
||||
code: 'countdown_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.countdown,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(icon: '', value: 0),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'Light 2 Switch',
|
||||
operationName: 'M - Light Switch',
|
||||
code: 'switch_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
@ -36,11 +48,23 @@ class ThreeGangHelperFunctions {
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'M - Light Countdown',
|
||||
code: 'countdown_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.countdown,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(icon: '', value: 0),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'Light 3 Switch',
|
||||
operationName: 'R - Light Switch',
|
||||
code: 'switch_3',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
@ -55,31 +79,7 @@ class ThreeGangHelperFunctions {
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'Light 1 CountDown',
|
||||
code: 'countdown_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.countdown,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(icon: '', value: 0),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'Light 2 CountDown',
|
||||
code: 'countdown_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.countdown,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(icon: '', value: 0),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'Light 3 CountDown',
|
||||
operationName: 'R - Light Countdown',
|
||||
code: 'countdown_3',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.countdown,
|
||||
@ -97,7 +97,7 @@ class ThreeGangHelperFunctions {
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'Light 1 Switch',
|
||||
operationName: 'L - Light Switch',
|
||||
code: 'switch_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
@ -108,41 +108,11 @@ class ThreeGangHelperFunctions {
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'Light 2 Switch',
|
||||
code: 'switch_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'Light 3 Switch',
|
||||
code: 'switch_3',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'Light 1 CountDown',
|
||||
operationName: 'L - Light Countdown',
|
||||
code: 'countdown_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.integerSteps,
|
||||
@ -157,11 +127,26 @@ class ThreeGangHelperFunctions {
|
||||
),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'M - Light Switch',
|
||||
code: 'switch_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'Light 2 CountDown',
|
||||
operationName: 'M - Light Countdown',
|
||||
code: 'countdown_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.integerSteps,
|
||||
@ -176,11 +161,26 @@ class ThreeGangHelperFunctions {
|
||||
),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'R - Light Switch',
|
||||
code: 'switch_3',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'Light 3 CountDown',
|
||||
operationName: 'R - Light Countdown',
|
||||
code: 'countdown_3',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.integerSteps,
|
||||
|
@ -0,0 +1,139 @@
|
||||
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
|
||||
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
|
||||
class TowGangHelperFunctions {
|
||||
static List<SceneStaticFunction> towGangHelperFunctions(
|
||||
String deviceId, String deviceName, functionValue) {
|
||||
return [
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'L - Light Switch',
|
||||
code: 'switch_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'L - Light CountDown',
|
||||
code: 'countdown_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.countdown,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(icon: '', value: 0),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'R - Light Switch',
|
||||
code: 'switch_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'R - Light CountDown',
|
||||
code: 'countdown_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.countdown,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(icon: '', value: 0),
|
||||
],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
static List<SceneStaticFunction> towGangAutomationFunctions(
|
||||
String deviceId, String deviceName, functionValue) {
|
||||
return [
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'L - Light Switch',
|
||||
code: 'switch_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'R - Light CountDown',
|
||||
code: 'countdown_1',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.integerSteps,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: '',
|
||||
description: "sec",
|
||||
value: 0.0,
|
||||
minValue: 0,
|
||||
maxValue: 43200,
|
||||
stepValue: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsAcPower,
|
||||
operationName: 'R - Light Switch',
|
||||
code: 'switch_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.onOff,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPower, description: "ON", value: true),
|
||||
SceneOperationalValue(
|
||||
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
|
||||
],
|
||||
),
|
||||
SceneStaticFunction(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
icon: Assets.assetsLightCountdown,
|
||||
operationName: 'R - Light CountDown',
|
||||
code: 'countdown_2',
|
||||
functionValue: functionValue,
|
||||
operationDialogType: OperationDialogType.integerSteps,
|
||||
operationalValues: [
|
||||
SceneOperationalValue(
|
||||
icon: '',
|
||||
description: "sec",
|
||||
value: 0.0,
|
||||
minValue: 0,
|
||||
maxValue: 43200,
|
||||
stepValue: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -74,6 +74,9 @@ class Action {
|
||||
ExecutorProperty? executorProperty;
|
||||
String? name;
|
||||
String? type;
|
||||
final String productType;
|
||||
|
||||
final String deviceName;
|
||||
|
||||
Action({
|
||||
required this.actionExecutor,
|
||||
@ -81,6 +84,8 @@ class Action {
|
||||
this.executorProperty,
|
||||
this.name,
|
||||
this.type,
|
||||
required this.productType,
|
||||
required this.deviceName,
|
||||
});
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
@ -88,10 +93,12 @@ class Action {
|
||||
static Action? fromJson(Map<String, dynamic> json) {
|
||||
if (json['name'] != null && json['type'] != null) {
|
||||
return Action(
|
||||
actionExecutor: json["actionExecutor"],
|
||||
entityId: json["entityId"],
|
||||
name: json['name'],
|
||||
type: json['type'],
|
||||
actionExecutor: json["actionExecutor"] as String,
|
||||
entityId: json["entityId"] as String,
|
||||
name: json['name'] as String?,
|
||||
type: json['type'] as String?,
|
||||
productType: json['productType'] as String,
|
||||
deviceName: json['deviceName'] as String,
|
||||
);
|
||||
}
|
||||
if (json["executorProperty"] == null) {
|
||||
@ -99,9 +106,11 @@ class Action {
|
||||
}
|
||||
|
||||
return Action(
|
||||
actionExecutor: json["actionExecutor"],
|
||||
entityId: json["entityId"],
|
||||
actionExecutor: json["actionExecutor"] as String,
|
||||
entityId: json["entityId"] as String,
|
||||
executorProperty: ExecutorProperty.fromJson(json["executorProperty"]),
|
||||
productType: json['productType'] as String,
|
||||
deviceName: json['deviceName'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@ -142,12 +151,16 @@ class Condition {
|
||||
final String entityId;
|
||||
final String entityType;
|
||||
final Expr expr;
|
||||
final String productType;
|
||||
final String deviceName;
|
||||
|
||||
Condition({
|
||||
required this.code,
|
||||
required this.entityId,
|
||||
required this.entityType,
|
||||
required this.expr,
|
||||
required this.productType,
|
||||
required this.deviceName,
|
||||
});
|
||||
|
||||
factory Condition.fromRawJson(String str) =>
|
||||
@ -160,6 +173,8 @@ class Condition {
|
||||
entityId: json["entityId"],
|
||||
entityType: json["entityType"],
|
||||
expr: Expr.fromJson(json["expr"]),
|
||||
productType: json['productType'] as String,
|
||||
deviceName: json['deviceName'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
|
||||
@ -11,11 +12,10 @@ import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/light_divider.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/navigation/navigate_to_route.dart';
|
||||
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class DeviceFunctionsView extends StatelessWidget
|
||||
@ -51,22 +51,14 @@ class DeviceFunctionsView extends StatelessWidget
|
||||
.add(AddTaskEvent(isAutomation: isAutomation));
|
||||
navigateToRoute(context, Routes.sceneTasksRoute);
|
||||
},
|
||||
child: BodyMedium(
|
||||
text: 'Save',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.secondaryColor.withOpacity(0.6),
|
||||
),
|
||||
child: SvgPicture.asset(Assets.saveRoutinesIcon),
|
||||
),
|
||||
],
|
||||
leading: TextButton(
|
||||
onPressed: () {
|
||||
_cancelOperation(context, device, isAutomation);
|
||||
},
|
||||
child: BodyMedium(
|
||||
text: 'Cancel',
|
||||
fontWeight: FontWeight.normal,
|
||||
fontColor: ColorsManager.textPrimaryColor.withOpacity(0.6),
|
||||
),
|
||||
child: SvgPicture.asset(Assets.cancelIcon),
|
||||
),
|
||||
leadingWidth: 80,
|
||||
padding: EdgeInsets.zero,
|
||||
@ -75,66 +67,127 @@ class DeviceFunctionsView extends StatelessWidget
|
||||
itemCount: functions.length,
|
||||
padding: const EdgeInsets.only(top: 24.0),
|
||||
itemBuilder: (context, index) {
|
||||
return DefaultContainer(
|
||||
padding: index == 0
|
||||
? const EdgeInsets.only(top: 8)
|
||||
: index == functions.length - 1
|
||||
? const EdgeInsets.only(bottom: 8)
|
||||
: EdgeInsets.zero,
|
||||
margin: EdgeInsets.zero,
|
||||
borderRadius: index == 0
|
||||
? const BorderRadius.only(
|
||||
topLeft: Radius.circular(20), topRight: Radius.circular(20))
|
||||
: index == functions.length - 1
|
||||
? const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(20),
|
||||
bottomRight: Radius.circular(20))
|
||||
: BorderRadius.zero,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
BlocBuilder<CreateSceneBloc, CreateSceneState>(
|
||||
builder: (context, state) {
|
||||
return SceneListTile(
|
||||
iconsSize: 22,
|
||||
minLeadingWidth: 20,
|
||||
assetPath: functions[index].icon,
|
||||
titleString: functions[index].operationName,
|
||||
trailingWidget: const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
if (device.productType!.name.toString() == 'ThreeGang' ||
|
||||
device.productType!.name.toString() == 'TwoGang') {
|
||||
final bool isFirstInPair = index % 2 == 0;
|
||||
final bool isLastInPair =
|
||||
index % 2 == 1 || index == functions.length - 1;
|
||||
final bool isLastItem = index == functions.length - 1;
|
||||
return Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
if (isFirstInPair && index != 0) const SizedBox(height: 16),
|
||||
DefaultContainer(
|
||||
padding: EdgeInsets.only(
|
||||
top: isFirstInPair ? 8 : 0,
|
||||
bottom: isLastInPair ? 8 : 0,
|
||||
),
|
||||
margin: EdgeInsets.zero,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(isFirstInPair ? 20 : 0),
|
||||
topRight: Radius.circular(isFirstInPair ? 20 : 0),
|
||||
bottomLeft: Radius.circular(isLastInPair ? 20 : 0),
|
||||
bottomRight: Radius.circular(isLastInPair ? 20 : 0),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
BlocBuilder<CreateSceneBloc, CreateSceneState>(
|
||||
builder: (context, state) {
|
||||
return SceneListTile(
|
||||
iconsSize: 22,
|
||||
minLeadingWidth: 20,
|
||||
assetPath: functions[index].icon,
|
||||
titleString: functions[index].operationName,
|
||||
trailingWidget: const Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
onPressed: () {
|
||||
if (isAutomation) {
|
||||
_showAutomationDialog(
|
||||
context,
|
||||
functions[index],
|
||||
device,
|
||||
);
|
||||
} else {
|
||||
_showTabToRunDialog(
|
||||
context,
|
||||
functions[index],
|
||||
device,
|
||||
);
|
||||
}
|
||||
onPressed: () {
|
||||
if (isAutomation) {
|
||||
_showAutomationDialog(
|
||||
context, functions[index], device);
|
||||
} else {
|
||||
_showTabToRunDialog(
|
||||
context, functions[index], device);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
if (isFirstInPair && !isLastItem)
|
||||
SizedBox(
|
||||
width: context.width * 0.8,
|
||||
child: const LightDivider(),
|
||||
),
|
||||
],
|
||||
),
|
||||
index != functions.length - 1
|
||||
? SizedBox(
|
||||
width: context.width * 0.8, child: const LightDivider())
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
);
|
||||
)
|
||||
]);
|
||||
} else {
|
||||
return DefaultContainer(
|
||||
padding: index == 0
|
||||
? const EdgeInsets.only(top: 8)
|
||||
: index == functions.length - 1
|
||||
? const EdgeInsets.only(bottom: 8)
|
||||
: EdgeInsets.zero,
|
||||
margin: EdgeInsets.zero,
|
||||
borderRadius: index == 0 && index == functions.length - 1
|
||||
? const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
bottomLeft: Radius.circular(20),
|
||||
bottomRight: Radius.circular(20),
|
||||
)
|
||||
: index == 0
|
||||
? const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
)
|
||||
: index == functions.length - 1
|
||||
? const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(20),
|
||||
bottomRight: Radius.circular(20),
|
||||
)
|
||||
: BorderRadius.zero,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
BlocBuilder<CreateSceneBloc, CreateSceneState>(
|
||||
builder: (context, state) {
|
||||
return SceneListTile(
|
||||
iconsSize: 22,
|
||||
minLeadingWidth: 20,
|
||||
assetPath: functions[index].icon,
|
||||
titleString: functions[index].operationName,
|
||||
trailingWidget: const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
onPressed: () {
|
||||
if (isAutomation) {
|
||||
_showAutomationDialog(
|
||||
context, functions[index], device);
|
||||
} else {
|
||||
_showTabToRunDialog(
|
||||
context, functions[index], device);
|
||||
}
|
||||
},
|
||||
);
|
||||
}),
|
||||
index != functions.length - 1
|
||||
? SizedBox(
|
||||
width: context.width * 0.8,
|
||||
child: const LightDivider())
|
||||
: const SizedBox(),
|
||||
],
|
||||
));
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -20,82 +20,69 @@ class SceneRoomsTabBarDevicesView extends StatefulWidget {
|
||||
_SceneRoomsTabBarDevicesViewState();
|
||||
}
|
||||
|
||||
class _SceneRoomsTabBarDevicesViewState
|
||||
extends State<SceneRoomsTabBarDevicesView>
|
||||
class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesView>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final TabController _tabController;
|
||||
List<SubSpaceModel>? rooms = [];
|
||||
late final SpaceModel selectedSpace;
|
||||
var rooms = <SubSpaceModel>[];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
selectedSpace = HomeCubit.getInstance().selectedSpace!;
|
||||
selectedSpace = HomeCubit.getInstance().selectedSpace!;
|
||||
|
||||
rooms = List.from(selectedSpace.subspaces ?? []);
|
||||
rooms = List.from(selectedSpace.subspaces);
|
||||
final defaultSubSpaceModel = SubSpaceModel(
|
||||
name: 'All Devices',
|
||||
devices: context.read<DevicesCubit>().allDevices,
|
||||
id: '-1',
|
||||
);
|
||||
|
||||
if (rooms != null && rooms!.isNotEmpty) {
|
||||
if (rooms![0].id != '-1') {
|
||||
rooms?.insert(
|
||||
0,
|
||||
SubSpaceModel(
|
||||
name: 'All Devices',
|
||||
devices: context.read<DevicesCubit>().allDevices,
|
||||
id: '-1',
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
rooms = [
|
||||
SubSpaceModel(
|
||||
name: 'All Devices',
|
||||
devices: context.read<DevicesCubit>().allDevices,
|
||||
id: '-1',
|
||||
)
|
||||
];
|
||||
if (rooms.isNotEmpty) {
|
||||
final isFirstRoomIdValid = rooms[0].id != '-1';
|
||||
if (isFirstRoomIdValid) {
|
||||
rooms.insert(0, defaultSubSpaceModel);
|
||||
}
|
||||
|
||||
_tabController = TabController(length: rooms!.length, vsync: this);
|
||||
_tabController.addListener(_handleTabSwitched);
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
void _handleTabSwitched() {
|
||||
if (_tabController.indexIsChanging) {
|
||||
final value = _tabController.index;
|
||||
|
||||
/// select tab
|
||||
context.read<TabBarBloc>().add(TabChanged(
|
||||
selectedIndex: value,
|
||||
roomId: rooms?[value].id ?? '',
|
||||
unit: selectedSpace));
|
||||
return;
|
||||
} else {
|
||||
rooms = [defaultSubSpaceModel];
|
||||
}
|
||||
|
||||
_tabController = TabController(length: rooms.length, vsync: this);
|
||||
_tabController.addListener(_handleTabSwitched);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_tabController.dispose();
|
||||
_tabController.removeListener(() {});
|
||||
_tabController.dispose();
|
||||
}
|
||||
|
||||
void _handleTabSwitched() {
|
||||
if (_tabController.indexIsChanging) {
|
||||
final index = _tabController.index;
|
||||
|
||||
context.read<TabBarBloc>().add(
|
||||
TabBarTabChangedEvent(
|
||||
selectedIndex: index,
|
||||
roomId: rooms[index].id ?? '',
|
||||
unit: selectedSpace,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: StringsManager.createScene,
|
||||
padding: EdgeInsets.zero,
|
||||
padding: EdgeInsetsDirectional.zero,
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
navigateToRoute(context, Routes.sceneTasksRoute);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_ios,
|
||||
),
|
||||
onPressed: () => navigateToRoute(context, Routes.sceneTasksRoute),
|
||||
icon: const Icon(Icons.arrow_back_ios),
|
||||
),
|
||||
title: StringsManager.createScene,
|
||||
child: SceneDevicesBody(tabController: _tabController, rooms: rooms),
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
@ -8,60 +7,44 @@ import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_bloc.dart'
|
||||
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_state.dart';
|
||||
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
|
||||
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
|
||||
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
import 'package:syncrow_app/features/scene/widgets/scene_devices/scene_devices_body_tab_bar.dart';
|
||||
import 'package:syncrow_app/features/scene/widgets/scene_devices/scene_devices_list.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/app_loading_indicator.dart';
|
||||
|
||||
class SceneDevicesBody extends StatelessWidget {
|
||||
const SceneDevicesBody({
|
||||
super.key,
|
||||
required TabController tabController,
|
||||
required this.tabController,
|
||||
required this.rooms,
|
||||
}) : _tabController = tabController;
|
||||
super.key,
|
||||
});
|
||||
|
||||
final TabController _tabController;
|
||||
final List<SubSpaceModel>? rooms;
|
||||
final TabController tabController;
|
||||
final List<SubSpaceModel> rooms;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isAutomationDeviceStatus =
|
||||
((ModalRoute.of(context)?.settings.arguments as SceneSettingsRouteArguments?)?.sceneType ==
|
||||
CreateSceneEnum.deviceStatusChanges.name);
|
||||
return BlocBuilder<TabBarBloc, TabBarState>(
|
||||
builder: (context, tabState) {
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TabBar(
|
||||
controller: _tabController,
|
||||
dividerColor: Colors.transparent,
|
||||
indicatorColor: Colors.transparent,
|
||||
tabs: [
|
||||
...rooms!.map((e) => Tab(
|
||||
child: BodyLarge(
|
||||
text: e.name ?? '',
|
||||
textAlign: TextAlign.start,
|
||||
style: context.bodyLarge.copyWith(
|
||||
color: (tabState is TabSelected) && tabState.roomId == e.id
|
||||
? ColorsManager.textPrimaryColor
|
||||
: ColorsManager.textPrimaryColor.withOpacity(0.2),
|
||||
),
|
||||
),
|
||||
)),
|
||||
],
|
||||
isScrollable: true,
|
||||
tabAlignment: TabAlignment.start,
|
||||
SceneDevicesBodyTabBar(
|
||||
tabController: tabController,
|
||||
rooms: rooms,
|
||||
selectedRoomId: state is TabBarTabSelectedState ? state.roomId : '-1',
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children:
|
||||
rooms!.map((e) => _buildRoomTab(e, context, isAutomationDeviceStatus)).toList(),
|
||||
controller: tabController,
|
||||
children: rooms
|
||||
.map(
|
||||
(room) => _buildRoomTab(
|
||||
room,
|
||||
_isAutomationDeviceStatus(context),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -70,52 +53,46 @@ class SceneDevicesBody extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRoomTab(SubSpaceModel room, BuildContext context, bool isAutomationDeviceStatus) {
|
||||
bool _isAutomationDeviceStatus(BuildContext context) {
|
||||
final routeArguments =
|
||||
ModalRoute.of(context)?.settings.arguments as SceneSettingsRouteArguments?;
|
||||
final deviceStatusChangesScene = CreateSceneEnum.deviceStatusChanges.name;
|
||||
final sceneType = routeArguments?.sceneType;
|
||||
|
||||
return sceneType == deviceStatusChangesScene;
|
||||
}
|
||||
|
||||
Widget _buildRoomTab(
|
||||
SubSpaceModel room,
|
||||
bool isAutomationDeviceStatus,
|
||||
) {
|
||||
return BlocBuilder<DeviceManagerBloc, DeviceManagerState>(
|
||||
builder: (context, state) {
|
||||
if (state.loading && state.devices == null) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state.devices != null && state.devices!.isNotEmpty) {
|
||||
return ListView.builder(
|
||||
itemCount: state.devices!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final device = state.devices![index];
|
||||
return DefaultContainer(
|
||||
child: SceneListTile(
|
||||
minLeadingWidth: 40,
|
||||
leadingWidget: SvgPicture.asset(device.icon ?? ''),
|
||||
titleWidget: BodyMedium(
|
||||
text: device.name ?? '',
|
||||
style: context.titleSmall.copyWith(
|
||||
color: ColorsManager.secondaryTextColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
trailingWidget: const Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 16,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.deviceFunctionsRoute,
|
||||
arguments: {
|
||||
"device": device,
|
||||
"isAutomationDeviceStatus": isAutomationDeviceStatus
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else if (state.error != null) {
|
||||
return const Center(child: Text('Something went wrong'));
|
||||
} else {
|
||||
return const SizedBox();
|
||||
}
|
||||
final isLoading = state.loading && state.devices == null;
|
||||
final hasData =
|
||||
state.devices != null && (state.devices?.isNotEmpty ?? false);
|
||||
final hasError = state.error != null;
|
||||
|
||||
final widgets = <bool, Widget>{
|
||||
isLoading: const AppLoadingIndicator(),
|
||||
hasError: Center(child: Text('${state.error}')),
|
||||
hasData: SceneDevicesList(
|
||||
devices: state.devices ?? [],
|
||||
isAutomationDeviceStatus: isAutomationDeviceStatus,
|
||||
),
|
||||
};
|
||||
|
||||
final invalidWidgetEntry = MapEntry(
|
||||
true,
|
||||
Center(child: Text('This subspace has no devices')),
|
||||
);
|
||||
|
||||
final validWidgetEntry = widgets.entries.firstWhere(
|
||||
(entry) => entry.key == true,
|
||||
orElse: () => invalidWidgetEntry,
|
||||
);
|
||||
|
||||
return validWidgetEntry.value;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class SceneDevicesBodyTabBar extends StatelessWidget {
|
||||
const SceneDevicesBodyTabBar({
|
||||
required this.tabController,
|
||||
required this.rooms,
|
||||
required this.selectedRoomId,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String selectedRoomId;
|
||||
|
||||
final TabController tabController;
|
||||
final List<SubSpaceModel> rooms;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TabBar(
|
||||
controller: tabController,
|
||||
dividerColor: Colors.transparent,
|
||||
indicatorColor: Colors.transparent,
|
||||
isScrollable: true,
|
||||
tabAlignment: TabAlignment.start,
|
||||
tabs: rooms.map((e) {
|
||||
final isSelected = selectedRoomId == e.id;
|
||||
return Tab(
|
||||
child: BodyLarge(
|
||||
text: e.name ?? '',
|
||||
textAlign: TextAlign.start,
|
||||
style: context.bodyLarge.copyWith(
|
||||
color: isSelected
|
||||
? ColorsManager.textPrimaryColor
|
||||
: ColorsManager.textPrimaryColor.withValues(
|
||||
alpha: 0.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class SceneDevicesList extends StatelessWidget {
|
||||
const SceneDevicesList({
|
||||
required this.isAutomationDeviceStatus,
|
||||
required this.devices,
|
||||
super.key,
|
||||
});
|
||||
final List<DeviceModel> devices;
|
||||
final bool isAutomationDeviceStatus;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
itemCount: devices.length,
|
||||
itemBuilder: (context, index) => _buildDeviceTile(context, devices[index]),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDeviceTile(
|
||||
BuildContext context,
|
||||
DeviceModel device,
|
||||
) {
|
||||
return DefaultContainer(
|
||||
child: SceneListTile(
|
||||
minLeadingWidth: 40,
|
||||
leadingWidget: SvgPicture.asset(device.icon ?? ''),
|
||||
titleWidget: BodyMedium(
|
||||
text: device.name ?? '',
|
||||
style: context.titleSmall.copyWith(
|
||||
color: ColorsManager.secondaryTextColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
trailingWidget: const Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 16,
|
||||
),
|
||||
onPressed: () => _navigateToDeviceFunctions(context, device),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _navigateToDeviceFunctions(
|
||||
BuildContext context,
|
||||
DeviceModel device,
|
||||
) {
|
||||
Navigator.of(context).pushNamed(
|
||||
Routes.deviceFunctionsRoute,
|
||||
arguments: {
|
||||
"device": device,
|
||||
"isAutomationDeviceStatus": isAutomationDeviceStatus,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1142,5 +1142,9 @@ class Assets {
|
||||
|
||||
static const String toggleSwitchSmall = 'assets/icons/toggleSwitchSmall.svg';
|
||||
static const String offToggleSwitchSmall = 'assets/icons/offToggleSwitchSmall.svg';
|
||||
static const String saveRoutinesIcon = 'assets/icons/save_routines_icon.svg';
|
||||
static const String cancelIcon = 'assets/icons/cancel_icon.svg';
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/app_layout/model/community_model.dart';
|
||||
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
|
||||
import 'package:syncrow_app/features/app_layout/view/app_layout.dart';
|
||||
import 'package:syncrow_app/features/auth/view/otp_view.dart';
|
||||
import 'package:syncrow_app/features/auth/view/login_view.dart';
|
||||
import 'package:syncrow_app/features/auth/view/otp_view.dart';
|
||||
import 'package:syncrow_app/features/auth/view/sign_up_view.dart';
|
||||
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_bloc.dart';
|
||||
@ -17,11 +17,12 @@ import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_bloc.dart'
|
||||
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart';
|
||||
import 'package:syncrow_app/features/scene/view/device_functions_view.dart';
|
||||
import 'package:syncrow_app/features/scene/view/scene_auto_settings.dart';
|
||||
import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart';
|
||||
import 'package:syncrow_app/features/scene/view/scene_rooms_tabbar.dart';
|
||||
import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart';
|
||||
import 'package:syncrow_app/features/scene/view/scene_view.dart';
|
||||
import 'package:syncrow_app/features/scene/view/smart_automation_select_route.dart';
|
||||
import 'package:syncrow_app/features/splash/view/splash_view.dart';
|
||||
|
||||
import 'routing_constants.dart';
|
||||
|
||||
class Router {
|
||||
@ -88,7 +89,7 @@ class Router {
|
||||
BlocProvider(
|
||||
create: (BuildContext context) =>
|
||||
TabBarBloc(context.read<DeviceManagerBloc>())
|
||||
..add(TabChanged(
|
||||
..add(TabBarTabChangedEvent(
|
||||
selectedIndex: 0,
|
||||
roomId: '-1',
|
||||
unit: SpaceModel(
|
||||
|
@ -11,7 +11,7 @@ abstract class ApiEndpoints {
|
||||
static const String sendOtp = '/authentication/user/send-otp';
|
||||
static const String verifyOtp = '/authentication/user/verify-otp';
|
||||
static const String forgetPassword = '/authentication/user/forget-password';
|
||||
|
||||
static const String clientLogin = '/client/token';
|
||||
////////////////////////////////////// Spaces ///////////////////////////////////////
|
||||
|
||||
///Community Module
|
||||
|
@ -25,11 +25,15 @@ class AuthenticationAPI {
|
||||
return response;
|
||||
}
|
||||
|
||||
static Future<bool> signUp({required SignUpModel model}) async {
|
||||
static Future<bool> signUp({
|
||||
required SignUpModel model,
|
||||
required String accessToken,
|
||||
}) async {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.signUp,
|
||||
body: model.toJson(),
|
||||
showServerMessage: false,
|
||||
accessToken: accessToken,
|
||||
expectedResponseModel: (json) => json['statusCode'] == 201);
|
||||
return response;
|
||||
}
|
||||
@ -63,4 +67,20 @@ class AuthenticationAPI {
|
||||
expectedResponseModel: (json) => json['data']);
|
||||
return response;
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> fetchClientToken({
|
||||
required String clientId,
|
||||
required String clientSecret,
|
||||
}) async {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.clientLogin,
|
||||
body: {
|
||||
'clientId': clientId,
|
||||
'clientSecret': clientSecret,
|
||||
},
|
||||
showServerMessage: false,
|
||||
expectedResponseModel: (json) => json['data'],
|
||||
);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -48,13 +48,26 @@ class HTTPService {
|
||||
Options? options,
|
||||
dynamic body,
|
||||
bool showServerMessage = true,
|
||||
String? accessToken,
|
||||
required T Function(dynamic) expectedResponseModel}) async {
|
||||
try {
|
||||
final authOptions = options ??
|
||||
Options(
|
||||
headers: accessToken != null
|
||||
? {
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
final response = await client.post(
|
||||
path,
|
||||
data: body,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
options: authOptions,
|
||||
);
|
||||
return expectedResponseModel(response.data);
|
||||
} catch (error) {
|
||||
|
Reference in New Issue
Block a user