mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-11 07:38:05 +00:00
Compare commits
44 Commits
chore/remo
...
side_tree
Author | SHA1 | Date | |
---|---|---|---|
132cafcaa2 | |||
572520eed5 | |||
506531e16a | |||
5ae07688cb | |||
6e546a4831 | |||
b098202fd8 | |||
a294988558 | |||
43c17d1c18 | |||
09c1a785e5 | |||
e70b9ea9e2 | |||
c173df934d | |||
e4262d08a5 | |||
4bae7bb9fb | |||
073916d4ac | |||
8870467fe4 | |||
9331193e90 | |||
45b0b67fe0 | |||
9e0184f19d | |||
9091af2661 | |||
4b7f4d4279 | |||
e61cfd7e49 | |||
788fb75a68 | |||
ea5b6597f5 | |||
c72297e0c8 | |||
d0c6b13072 | |||
812dc4792b | |||
4907eebc42 | |||
2221d9ae7b | |||
9167c8da29 | |||
4258ccdfbd | |||
cb71b51565 | |||
d4ed4efcd8 | |||
dac045146e | |||
5563197e9d | |||
7268253e35 | |||
921d352207 | |||
24f7ab6af8 | |||
2fb6f30ccb | |||
508d8bbaa8 | |||
65d00c923a | |||
5060d2a66d | |||
540f569b1f | |||
a98f7e77a3 | |||
0341844ea9 |
16
assets/icons/duplicate.svg
Normal file
16
assets/icons/duplicate.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.9807 2.67199L16.6413 0.219727H7.91051C7.43122 0.219727 7.04266 0.608281 7.04266 1.08758V16.605C7.04266 17.0843 7.43122 17.4729 7.91051 17.4729H18.2257C18.705 17.4729 19.0935 17.0843 19.0935 16.605V16.5459H19.7312V3.8127L17.9807 2.67199Z" fill="#60B7FF"/>
|
||||
<path d="M18.1513 6.23445H9.12553C8.95881 6.23445 8.82373 6.09934 8.82373 5.93266C8.82373 5.76598 8.95885 5.63086 9.12553 5.63086H18.1513C18.318 5.63086 18.4531 5.76598 18.4531 5.93266C18.4531 6.09934 18.318 6.23445 18.1513 6.23445Z" fill="#0055A3"/>
|
||||
<path d="M18.1513 8.54891H9.12553C8.95881 8.54891 8.82373 8.41379 8.82373 8.24711C8.82373 8.08043 8.95885 7.94531 9.12553 7.94531H18.1513C18.318 7.94531 18.4531 8.08043 18.4531 8.24711C18.4531 8.41379 18.318 8.54891 18.1513 8.54891Z" fill="#0055A3"/>
|
||||
<path d="M18.1513 10.8634H9.12553C8.95881 10.8634 8.82373 10.7282 8.82373 10.5616C8.82373 10.3949 8.95885 10.2598 9.12553 10.2598H18.1513C18.318 10.2598 18.4531 10.3949 18.4531 10.5616C18.4531 10.7282 18.318 10.8634 18.1513 10.8634Z" fill="#0055A3"/>
|
||||
<path d="M18.1513 13.1778H9.12556C8.95884 13.1778 8.82376 13.0427 8.82376 12.876C8.82376 12.7093 8.95888 12.5742 9.12556 12.5742H18.1513C18.3181 12.5742 18.4531 12.7093 18.4531 12.876C18.4531 13.0427 18.3181 13.1778 18.1513 13.1778Z" fill="#0055A3"/>
|
||||
<path d="M19.0935 3.39648V16.6044C19.0935 17.0837 18.7049 17.4722 18.2256 17.4722H19.3663C19.8456 17.4722 20.2342 17.0837 20.2342 16.6044V3.81203L19.0935 3.39648Z" fill="#26A6FE"/>
|
||||
<path d="M17.5091 3.8127H20.2342L16.6413 0.219727V2.94484C16.6413 3.42414 17.0298 3.8127 17.5091 3.8127Z" fill="#004281"/>
|
||||
<path d="M11.4172 19.7805C11.8965 19.7805 12.2851 19.392 12.2851 18.9127V18.8937H12.8297V6.12031L11.039 4.78906L9.83279 2.52734H1.10204C0.622747 2.52734 0.234192 2.9159 0.234192 3.3952V18.9127C0.234192 19.392 0.622747 19.7805 1.10204 19.7805H11.4172Z" fill="#D5EDFF"/>
|
||||
<path d="M12.285 4.97852V6.11922V18.9116C12.285 19.3909 11.8964 19.7794 11.4171 19.7794H12.5578C13.0371 19.7794 13.4257 19.3909 13.4257 18.9116V6.11922L12.285 4.97852Z" fill="#D8ECFE"/>
|
||||
<path d="M10.7006 6.12031H13.4258L9.83279 2.52734V5.25246C9.83276 5.73176 10.2213 6.12031 10.7006 6.12031Z" fill="#B3DAFE"/>
|
||||
<path d="M11.3429 8.54891H2.31709C2.15037 8.54891 2.01529 8.41379 2.01529 8.24711C2.01529 8.08043 2.15041 7.94531 2.31709 7.94531H11.3429C11.5096 7.94531 11.6447 8.08043 11.6447 8.24711C11.6447 8.41379 11.5096 8.54891 11.3429 8.54891Z" fill="#82AEE3"/>
|
||||
<path d="M11.3428 10.8634H2.31706C2.15034 10.8634 2.01526 10.7282 2.01526 10.5616C2.01526 10.3949 2.15038 10.2598 2.31706 10.2598H11.3428C11.5096 10.2598 11.6446 10.3949 11.6446 10.5616C11.6446 10.7282 11.5096 10.8634 11.3428 10.8634Z" fill="#82AEE3"/>
|
||||
<path d="M11.3428 13.1778H2.31706C2.15034 13.1778 2.01526 13.0427 2.01526 12.876C2.01526 12.7093 2.15038 12.5742 2.31706 12.5742H11.3428C11.5096 12.5742 11.6446 12.7093 11.6446 12.876C11.6446 13.0427 11.5096 13.1778 11.3428 13.1778Z" fill="#82AEE3"/>
|
||||
<path d="M11.3428 15.4923H2.31706C2.15034 15.4923 2.01526 15.3571 2.01526 15.1905C2.01526 15.0238 2.15038 14.8887 2.31706 14.8887H11.3428C11.5096 14.8887 11.6446 15.0238 11.6446 15.1905C11.6447 15.3571 11.5096 15.4923 11.3428 15.4923Z" fill="#82AEE3"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
22
assets/icons/edit_space.svg
Normal file
22
assets/icons/edit_space.svg
Normal file
@ -0,0 +1,22 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_d_4618_3290)">
|
||||
<path d="M18.7967 7.35156V19.8515C18.7967 21.0362 17.8329 22 16.6482 22H4.14825C2.9636 22 1.99982 21.0362 1.99982 19.8515V7.35156C1.99982 6.16691 2.9636 5.20312 4.14825 5.20312H16.6482C17.8329 5.20312 18.7967 6.16691 18.7967 7.35156Z" fill="#EDF2F2"/>
|
||||
<path d="M18.7967 19.8515C18.7967 21.0361 17.8329 21.9999 16.6482 21.9999H4.14825C3.55591 21.9999 3.0188 21.7589 2.62978 21.3699L18.1667 5.83301C18.5557 6.22203 18.7967 6.75914 18.7967 7.35148V19.8515Z" fill="#C9DCDC"/>
|
||||
<path d="M9.28417 14.7153C9.12722 14.5583 9.07241 14.3262 9.14265 14.1157L9.97128 11.6297C10 11.5434 10.0485 11.465 10.1128 11.4007L17.8468 3.66674C18.0756 3.43791 18.4466 3.43791 18.6754 3.66674L20.3327 5.324C20.5615 5.55283 20.5615 5.9238 20.3327 6.15263L12.5987 13.8866C12.5344 13.9509 12.456 13.9994 12.3697 14.0281L9.88374 14.8567C9.67323 14.927 9.44109 14.8722 9.28417 14.7153Z" fill="#4998EE"/>
|
||||
<path d="M19.504 4.49512L9.28413 14.715C9.44105 14.8719 9.6732 14.9267 9.88374 14.8565L12.3697 14.0279C12.456 13.9992 12.5344 13.9507 12.5987 13.8864L20.3327 6.15242C20.5615 5.92359 20.5615 5.55261 20.3327 5.32379L19.504 4.49512Z" fill="#176EDE"/>
|
||||
<path d="M20.3327 6.15305L17.8467 3.66711L19.2278 2.28602C19.6092 1.90466 20.2275 1.90466 20.6089 2.28602L21.7137 3.39087C22.0951 3.77223 22.0951 4.39055 21.7137 4.77192L20.3327 6.15305Z" fill="#FFE137"/>
|
||||
<path d="M21.1613 2.83789L19.0897 4.90949L20.3327 6.15245L21.7138 4.77136C22.0951 4.39 22.0951 3.77168 21.7138 3.39031L21.1613 2.83789Z" fill="#FAC814"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_d_4618_3290" x="-0.000183105" y="0" width="24" height="24" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset/>
|
||||
<feGaussianBlur stdDeviation="1"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4618_3290"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4618_3290" result="shape"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
9
assets/icons/space_delete.svg
Normal file
9
assets/icons/space_delete.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.8069 19.9998H3.50035C2.16411 19.9998 1.08087 18.9165 1.08087 17.5804V4.51562H14.2262V17.5804C14.2262 18.9165 13.1432 19.9998 11.8069 19.9998Z" fill="#D8D8D8"/>
|
||||
<path d="M1.08087 4.51562V5.48335H12.3715C12.8168 5.48335 13.1779 5.84438 13.1779 6.2898V17.3384C13.1779 18.2292 12.4557 18.9513 11.5649 18.9513H2.4519C2.05409 18.9513 1.67887 18.8547 1.34775 18.6844C1.74907 19.4652 2.56207 19.9998 3.50035 19.9998H11.8069C13.1432 19.9998 14.2262 18.9165 14.2262 17.5803V4.51562H1.08087Z" fill="#BABABA"/>
|
||||
<path d="M14.2667 1.77417H10.7439L10.1633 0.612956C9.9742 0.234837 9.5941 0 9.17142 0H6.13594C5.71311 0 5.33316 0.234837 5.1441 0.612956L4.56349 1.77417H1.04063C0.595221 1.77417 0.234192 2.1352 0.234192 2.58061V3.70978C0.234192 4.15504 0.595221 4.51622 1.04063 4.51622H14.2667C14.7121 4.51622 15.0732 4.15504 15.0732 3.70978V2.58077C15.0732 2.1352 14.7121 1.77417 14.2667 1.77417ZM5.68503 0.8835C5.77094 0.71153 5.94368 0.604869 6.13594 0.604869H9.17142C9.36354 0.604869 9.53627 0.71153 9.62218 0.8835L10.0676 1.77417H5.23977L5.68503 0.8835Z" fill="#757575"/>
|
||||
<path d="M14.2668 1.77441H12.9763C13.4217 1.77441 13.7829 2.13544 13.7829 2.58086V3.71003C13.7829 4.15529 13.4217 4.51647 12.9763 4.51647H14.2668C14.7122 4.51647 15.0732 4.15529 15.0732 3.71003V2.58101C15.0732 2.13544 14.7122 1.77441 14.2668 1.77441Z" fill="#595959"/>
|
||||
<path d="M11.3634 17.5C10.918 17.5 10.5569 17.139 10.5569 16.6935V9.15312C10.5569 8.70771 10.918 8.34668 11.3634 8.34668C11.8088 8.34668 12.1698 8.70771 12.1698 9.15312V16.6935C12.1698 17.139 11.8088 17.5 11.3634 17.5Z" fill="#757575"/>
|
||||
<path d="M3.94398 17.5C4.38924 17.5 4.75043 17.139 4.75043 16.6935V9.15312C4.75043 8.70771 4.38924 8.34668 3.94398 8.34668C3.49857 8.34668 3.13739 8.70771 3.13739 9.15312V16.6935C3.13739 17.139 3.49857 17.5 3.94398 17.5Z" fill="#757575"/>
|
||||
<path d="M7.65361 17.5C7.2082 17.5 6.84717 17.139 6.84717 16.6935V9.15312C6.84717 8.70771 7.2082 8.34668 7.65361 8.34668C8.09902 8.34668 8.46005 8.70771 8.46005 9.15312V16.6935C8.46005 17.139 8.09902 17.5 7.65361 17.5Z" fill="#757575"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
39
lib/common/edit_chip.dart
Normal file
39
lib/common/edit_chip.dart
Normal file
@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class EditChip extends StatelessWidget {
|
||||
final String label;
|
||||
final VoidCallback onTap;
|
||||
final Color labelColor;
|
||||
final Color backgroundColor;
|
||||
final Color borderColor;
|
||||
final double borderRadius;
|
||||
|
||||
const EditChip({
|
||||
Key? key,
|
||||
this.label = 'Edit',
|
||||
required this.onTap,
|
||||
this.labelColor = ColorsManager.spaceColor,
|
||||
this.backgroundColor = ColorsManager.whiteColors,
|
||||
this.borderColor = ColorsManager.spaceColor,
|
||||
this.borderRadius = 16.0,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Chip(
|
||||
label: Text(
|
||||
label,
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: labelColor)
|
||||
),
|
||||
backgroundColor: backgroundColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
side: BorderSide(color: borderColor),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -46,10 +46,9 @@ class CustomSearchBar extends StatelessWidget {
|
||||
filled: true,
|
||||
fillColor: ColorsManager.textFieldGreyColor,
|
||||
hintText: hintText,
|
||||
hintStyle: TextStyle(
|
||||
color: Color(0xB2999999),
|
||||
hintStyle: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
fontSize: 12,
|
||||
fontFamily: 'Aftika',
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 0,
|
||||
letterSpacing: -0.24,
|
25
lib/common/widgets/spaces_side_tree.dart
Normal file
25
lib/common/widgets/spaces_side_tree.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
|
||||
class SpacesSideTree extends StatefulWidget {
|
||||
final List<CommunityModel> communities;
|
||||
final String? selectedSpaceUuid;
|
||||
const SpacesSideTree({
|
||||
super.key,
|
||||
required this.communities,
|
||||
this.selectedSpaceUuid,
|
||||
});
|
||||
|
||||
@override
|
||||
State<SpacesSideTree> createState() => _SpacesSideTreeState();
|
||||
}
|
||||
|
||||
class _SpacesSideTreeState extends State<SpacesSideTree> {
|
||||
String _searchQuery = '';
|
||||
String? _selectedSpaceUuid;
|
||||
String? _selectedId;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder();
|
||||
}
|
||||
}
|
@ -6,7 +6,9 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||
import 'package:syncrow_web/services/locator.dart';
|
||||
import 'package:syncrow_web/utils/app_routes.dart';
|
||||
@ -15,8 +17,7 @@ import 'package:syncrow_web/utils/theme/theme.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
try {
|
||||
const environment =
|
||||
String.fromEnvironment('FLAVOR', defaultValue: 'development');
|
||||
const environment = String.fromEnvironment('FLAVOR', defaultValue: 'development');
|
||||
await dotenv.load(fileName: '.env.$environment');
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
initialSetup();
|
||||
@ -48,14 +49,16 @@ class MyApp extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
||||
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
||||
BlocProvider<VisitorPasswordBloc>(
|
||||
create: (context) => VisitorPasswordBloc(),
|
||||
),
|
||||
BlocProvider<RoutineBloc>(
|
||||
create: (context) => RoutineBloc(),
|
||||
),
|
||||
BlocProvider<SpaceTreeBloc>(
|
||||
create: (context) => SpaceTreeBloc()..add(InitialEvent()),
|
||||
),
|
||||
],
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
|
@ -19,12 +19,14 @@ class DefaultButton extends StatelessWidget {
|
||||
this.padding,
|
||||
this.borderColor,
|
||||
this.elevation,
|
||||
this.borderWidth = 1.0,
|
||||
});
|
||||
final void Function()? onPressed;
|
||||
final Widget child;
|
||||
final double? height;
|
||||
final bool isSecondary;
|
||||
final double? borderRadius;
|
||||
final double borderWidth;
|
||||
final bool enabled;
|
||||
final double? padding;
|
||||
final bool isDone;
|
||||
@ -66,7 +68,10 @@ class DefaultButton extends StatelessWidget {
|
||||
}),
|
||||
shape: WidgetStateProperty.all(
|
||||
RoundedRectangleBorder(
|
||||
side: BorderSide(color: borderColor ?? Colors.transparent),
|
||||
side: BorderSide(
|
||||
color: borderColor ?? Colors.transparent,
|
||||
width: borderWidth,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(borderRadius ?? 20),
|
||||
),
|
||||
),
|
||||
|
@ -1,13 +1,14 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
|
||||
part 'device_managment_event.dart';
|
||||
part 'device_managment_state.dart';
|
||||
|
||||
class DeviceManagementBloc
|
||||
extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||
class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||
int _selectedIndex = 0;
|
||||
List<AllDevicesModel> _devices = [];
|
||||
int _onlineCount = 0;
|
||||
@ -30,11 +31,23 @@ class DeviceManagementBloc
|
||||
on<UpdateSelection>(_onUpdateSelection);
|
||||
}
|
||||
|
||||
Future<void> _onFetchDevices(
|
||||
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
Future<void> _onFetchDevices(FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
emit(DeviceManagementLoading());
|
||||
try {
|
||||
final devices = await DevicesManagementApi().fetchDevices();
|
||||
List<AllDevicesModel> devices = [];
|
||||
_devices.clear();
|
||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
||||
devices = await DevicesManagementApi().fetchDevices('', '');
|
||||
} else {
|
||||
for (var community in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList = spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
||||
for (var space in spacesList) {
|
||||
devices.addAll(await DevicesManagementApi().fetchDevices(community, space));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_selectedDevices.clear();
|
||||
_devices = devices;
|
||||
_filteredDevices = devices;
|
||||
@ -53,8 +66,7 @@ class DeviceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
void _onFilterDevices(
|
||||
FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
void _onFilterDevices(FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
if (_devices.isNotEmpty) {
|
||||
_filteredDevices = List.from(_devices.where((device) {
|
||||
switch (event.filter) {
|
||||
@ -85,8 +97,7 @@ class DeviceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onResetFilters(
|
||||
ResetFilters event, Emitter<DeviceManagementState> emit) async {
|
||||
Future<void> _onResetFilters(ResetFilters event, Emitter<DeviceManagementState> emit) async {
|
||||
currentProductName = '';
|
||||
_selectedDevices.clear();
|
||||
_filteredDevices = List.from(_devices);
|
||||
@ -102,8 +113,7 @@ class DeviceManagementBloc
|
||||
));
|
||||
}
|
||||
|
||||
void _onResetSelectedDevices(
|
||||
ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
|
||||
void _onResetSelectedDevices(ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
|
||||
_selectedDevices.clear();
|
||||
|
||||
if (state is DeviceManagementLoaded) {
|
||||
@ -129,14 +139,12 @@ class DeviceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
void _onSelectedFilterChanged(
|
||||
SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSelectedFilterChanged(SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
||||
_selectedIndex = event.selectedIndex;
|
||||
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
||||
}
|
||||
|
||||
void _onSelectDevice(
|
||||
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSelectDevice(SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||
final selectedUuid = event.selectedDevice.uuid;
|
||||
|
||||
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
||||
@ -147,8 +155,7 @@ class DeviceManagementBloc
|
||||
|
||||
List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
|
||||
|
||||
bool isControlButtonEnabled =
|
||||
_checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||
bool isControlButtonEnabled = _checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||
|
||||
if (state is DeviceManagementLoaded) {
|
||||
emit(DeviceManagementLoaded(
|
||||
@ -157,8 +164,7 @@ class DeviceManagementBloc
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
selectedDevice:
|
||||
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
isControlButtonEnabled: isControlButtonEnabled,
|
||||
));
|
||||
} else if (state is DeviceManagementFiltered) {
|
||||
@ -168,15 +174,13 @@ class DeviceManagementBloc
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
selectedDevice:
|
||||
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
isControlButtonEnabled: isControlButtonEnabled,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _onUpdateSelection(
|
||||
UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||
void _onUpdateSelection(UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||
List<AllDevicesModel> selectedDevices = [];
|
||||
List<AllDevicesModel> devicesToSelectFrom = [];
|
||||
|
||||
@ -219,8 +223,7 @@ class DeviceManagementBloc
|
||||
|
||||
bool _checkIfControlButtonEnabled(List<AllDevicesModel> selectedDevices) {
|
||||
if (selectedDevices.length > 1) {
|
||||
final productTypes =
|
||||
selectedDevices.map((device) => device.productType).toSet();
|
||||
final productTypes = selectedDevices.map((device) => device.productType).toSet();
|
||||
return productTypes.length == 1;
|
||||
} else if (selectedDevices.length == 1) {
|
||||
return true;
|
||||
@ -231,10 +234,8 @@ class DeviceManagementBloc
|
||||
void _calculateDeviceCounts() {
|
||||
_onlineCount = _devices.where((device) => device.online == true).length;
|
||||
_offlineCount = _devices.where((device) => device.online == false).length;
|
||||
_lowBatteryCount = _devices
|
||||
.where((device) =>
|
||||
device.batteryLevel != null && device.batteryLevel! < 20)
|
||||
.length;
|
||||
_lowBatteryCount =
|
||||
_devices.where((device) => device.batteryLevel != null && device.batteryLevel! < 20).length;
|
||||
}
|
||||
|
||||
String _getFilterFromIndex(int index) {
|
||||
@ -250,8 +251,7 @@ class DeviceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
void _onSearchDevices(
|
||||
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||
if ((event.community == null || event.community!.isEmpty) &&
|
||||
(event.unitName == null || event.unitName!.isEmpty) &&
|
||||
(event.productName == null || event.productName!.isEmpty)) {
|
||||
@ -280,33 +280,22 @@ class DeviceManagementBloc
|
||||
final filteredDevices = devicesToSearch.where((device) {
|
||||
final matchesCommunity = event.community == null ||
|
||||
event.community!.isEmpty ||
|
||||
(device.community?.name
|
||||
?.toLowerCase()
|
||||
.contains(event.community!.toLowerCase()) ??
|
||||
(device.community?.name?.toLowerCase().contains(event.community!.toLowerCase()) ??
|
||||
false);
|
||||
final matchesUnit = event.unitName == null ||
|
||||
event.unitName!.isEmpty ||
|
||||
(device.spaces != null &&
|
||||
device.spaces!.isNotEmpty &&
|
||||
device.spaces![0].spaceName
|
||||
!.toLowerCase()
|
||||
.contains(event.unitName!.toLowerCase()));
|
||||
device.spaces![0].spaceName!.toLowerCase().contains(event.unitName!.toLowerCase()));
|
||||
final matchesProductName = event.productName == null ||
|
||||
event.productName!.isEmpty ||
|
||||
(device.name
|
||||
?.toLowerCase()
|
||||
.contains(event.productName!.toLowerCase()) ??
|
||||
false);
|
||||
(device.name?.toLowerCase().contains(event.productName!.toLowerCase()) ?? false);
|
||||
final matchesDeviceName = event.productName == null ||
|
||||
event.productName!.isEmpty ||
|
||||
(device.categoryName
|
||||
?.toLowerCase()
|
||||
.contains(event.productName!.toLowerCase()) ??
|
||||
(device.categoryName?.toLowerCase().contains(event.productName!.toLowerCase()) ??
|
||||
false);
|
||||
|
||||
return matchesCommunity &&
|
||||
matchesUnit &&
|
||||
(matchesProductName || matchesDeviceName);
|
||||
return matchesCommunity && matchesUnit && (matchesProductName || matchesDeviceName);
|
||||
}).toList();
|
||||
|
||||
emit(DeviceManagementFiltered(
|
||||
|
@ -7,7 +7,15 @@ abstract class DeviceManagementEvent extends Equatable {
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class FetchDevices extends DeviceManagementEvent {}
|
||||
class FetchDevices extends DeviceManagementEvent {
|
||||
// final Map<String, List<String>> selectedCommunitiesSpaces;
|
||||
// final String spaceId;
|
||||
final BuildContext context;
|
||||
|
||||
const FetchDevices(this.context);
|
||||
@override
|
||||
List<Object?> get props => [context];
|
||||
}
|
||||
|
||||
class FilterDevices extends DeviceManagementEvent {
|
||||
final String filter;
|
||||
|
@ -0,0 +1,47 @@
|
||||
class DeviceSubspace {
|
||||
final String uuid;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
final String subspaceName;
|
||||
final bool disabled;
|
||||
|
||||
DeviceSubspace({
|
||||
required this.uuid,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
required this.subspaceName,
|
||||
required this.disabled,
|
||||
});
|
||||
|
||||
factory DeviceSubspace.fromJson(Map<String, dynamic> json) {
|
||||
return DeviceSubspace(
|
||||
uuid: json['uuid'] as String,
|
||||
createdAt: json['createdAt'] != null
|
||||
? DateTime.tryParse(json['createdAt'].toString())
|
||||
: null,
|
||||
updatedAt: json['updatedAt'] != null
|
||||
? DateTime.tryParse(json['updatedAt'].toString())
|
||||
: null,
|
||||
subspaceName: json['subspaceName'] as String,
|
||||
disabled: json['disabled'] as bool,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'uuid': uuid,
|
||||
'createdAt': createdAt?.toIso8601String(),
|
||||
'updatedAt': updatedAt?.toIso8601String(),
|
||||
'subspaceName': subspaceName,
|
||||
'disabled': disabled,
|
||||
};
|
||||
}
|
||||
|
||||
static List<DeviceSubspace> listFromJson(List<dynamic> jsonList) {
|
||||
return jsonList.map((json) => DeviceSubspace.fromJson(json)).toList();
|
||||
}
|
||||
|
||||
static List<Map<String, dynamic>> listToJson(List<DeviceSubspace> subspaces) {
|
||||
return subspaces.map((subspace) => subspace.toJson()).toList();
|
||||
}
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_community.model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_subspace.model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/enum/device_types.dart';
|
||||
|
||||
@ -47,6 +48,7 @@ class AllDevicesModel {
|
||||
*/
|
||||
|
||||
DevicesModelRoom? room;
|
||||
DeviceSubspace? subspace;
|
||||
DevicesModelUnit? unit;
|
||||
DeviceCommunityModel? community;
|
||||
String? productUuid;
|
||||
@ -77,6 +79,7 @@ class AllDevicesModel {
|
||||
|
||||
AllDevicesModel({
|
||||
this.room,
|
||||
this.subspace,
|
||||
this.unit,
|
||||
this.community,
|
||||
this.productUuid,
|
||||
@ -110,6 +113,9 @@ class AllDevicesModel {
|
||||
room = (json['room'] != null && (json['room'] is Map))
|
||||
? DevicesModelRoom.fromJson(json['room'])
|
||||
: null;
|
||||
subspace = (json['subspace'] != null && (json['subspace'] is Map))
|
||||
? DeviceSubspace.fromJson(json['subspace'])
|
||||
: null;
|
||||
unit = (json['unit'] != null && (json['unit'] is Map))
|
||||
? DevicesModelUnit.fromJson(json['unit'])
|
||||
: null;
|
||||
@ -142,9 +148,7 @@ class AllDevicesModel {
|
||||
|
||||
productName = json['productName']?.toString();
|
||||
if (json['spaces'] != null && json['spaces'] is List) {
|
||||
spaces = (json['spaces'] as List)
|
||||
.map((space) => DeviceSpaceModel.fromJson(space))
|
||||
.toList();
|
||||
spaces = (json['spaces'] as List).map((space) => DeviceSpaceModel.fromJson(space)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,8 +196,7 @@ SOS
|
||||
String tempIcon = '';
|
||||
if (type == DeviceType.LightBulb) {
|
||||
tempIcon = Assets.lightBulb;
|
||||
} else if (type == DeviceType.CeilingSensor ||
|
||||
type == DeviceType.WallSensor) {
|
||||
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
|
||||
tempIcon = Assets.sensors;
|
||||
} else if (type == DeviceType.AC) {
|
||||
tempIcon = Assets.ac;
|
||||
@ -248,34 +251,25 @@ SOS
|
||||
case '1G':
|
||||
return [
|
||||
OneGangSwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
OneGangCountdownFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
OneGangCountdownFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
];
|
||||
|
||||
case '2G':
|
||||
return [
|
||||
TwoGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
];
|
||||
|
||||
case '3G':
|
||||
return [
|
||||
ThreeGangSwitch1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch3Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown3Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch3Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown3Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
];
|
||||
|
||||
default:
|
||||
@ -288,6 +282,9 @@ SOS
|
||||
if (room != null) {
|
||||
data['room'] = room!.toJson();
|
||||
}
|
||||
if (subspace != null) {
|
||||
data['subspace'] = subspace!.toJson();
|
||||
}
|
||||
if (unit != null) {
|
||||
data['unit'] = unit!.toJson();
|
||||
}
|
||||
@ -330,6 +327,7 @@ SOS
|
||||
|
||||
return other is AllDevicesModel &&
|
||||
other.room == room &&
|
||||
other.subspace == subspace &&
|
||||
other.unit == unit &&
|
||||
other.productUuid == productUuid &&
|
||||
other.productType == productType &&
|
||||
@ -360,6 +358,7 @@ SOS
|
||||
@override
|
||||
int get hashCode {
|
||||
return room.hashCode ^
|
||||
subspace.hashCode ^
|
||||
unit.hashCode ^
|
||||
productUuid.hashCode ^
|
||||
productType.hashCode ^
|
||||
|
@ -3,9 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/view/routines_view.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/view/create_new_routine_view.dart';
|
||||
import 'package:syncrow_web/pages/routines/view/routines_view.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
@ -19,7 +19,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (context) => DeviceManagementBloc()..add(FetchDevices()),
|
||||
create: (context) => DeviceManagementBloc()..add(FetchDevices(context)),
|
||||
),
|
||||
],
|
||||
child: WebScaffold(
|
||||
@ -80,7 +80,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
builder: (context, deviceState) {
|
||||
if (deviceState is DeviceManagementLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return const DeviceManagementBody(devices: []);
|
||||
} else if (deviceState is DeviceManagementLoaded) {
|
||||
return DeviceManagementBody(devices: deviceState.devices);
|
||||
} else if (deviceState is DeviceManagementFiltered) {
|
||||
|
@ -8,6 +8,8 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/format_date_time.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
@ -59,10 +61,23 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
|
||||
final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
|
||||
|
||||
return Column(
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(child: SpaceTreeView(
|
||||
onSelect: () {
|
||||
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||
},
|
||||
)),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: state is DeviceManagementLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
||||
padding: isLargeScreenSize(context)
|
||||
? const EdgeInsets.all(30)
|
||||
: const EdgeInsets.all(15),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -71,7 +86,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
tabs: tabs,
|
||||
selectedIndex: selectedIndex,
|
||||
onTabChanged: (index) {
|
||||
context.read<DeviceManagementBloc>().add(SelectedFilterChanged(index));
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(SelectedFilterChanged(index));
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
@ -93,7 +110,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
),
|
||||
);
|
||||
} else if (selectedDevices.length > 1) {
|
||||
final productTypes = selectedDevices.map((device) => device.productType).toSet();
|
||||
final productTypes = selectedDevices
|
||||
.map((device) => device.productType)
|
||||
.toSet();
|
||||
if (productTypes.length == 1) {
|
||||
showDialog(
|
||||
context: context,
|
||||
@ -122,13 +141,17 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
||||
padding: isLargeScreenSize(context)
|
||||
? const EdgeInsets.all(30)
|
||||
: const EdgeInsets.all(15),
|
||||
child: DynamicTable(
|
||||
withSelectAll: true,
|
||||
cellDecoration: containerDecoration,
|
||||
onRowSelected: (index, isSelected, row) {
|
||||
final selectedDevice = devicesToShow[index];
|
||||
context.read<DeviceManagementBloc>().add(SelectDevice(selectedDevice));
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(SelectDevice(selectedDevice));
|
||||
},
|
||||
withCheckBox: true,
|
||||
size: MediaQuery.of(context).size,
|
||||
@ -147,31 +170,45 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
data: devicesToShow.map((device) {
|
||||
final combinedSpaceNames = device.spaces != null
|
||||
? device.spaces!.map((space) => space.spaceName).join(' > ') +
|
||||
(device.community != null ? ' > ${device.community!.name}' : '')
|
||||
(device.community != null
|
||||
? ' > ${device.community!.name}'
|
||||
: '')
|
||||
: (device.community != null ? device.community!.name : '');
|
||||
|
||||
return [
|
||||
device.name ?? '',
|
||||
device.productName ?? '',
|
||||
device.uuid ?? '',
|
||||
(device.spaces != null && device.spaces!.isNotEmpty) ? device.spaces![0].spaceName : '',
|
||||
(device.spaces != null && device.spaces!.isNotEmpty)
|
||||
? device.spaces![0].spaceName
|
||||
: '',
|
||||
combinedSpaceNames,
|
||||
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||
(device.createTime ?? 0) * 1000)),
|
||||
device.online == true ? 'Online' : 'Offline',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||
(device.updateTime ?? 0) * 1000)),
|
||||
];
|
||||
}).toList(),
|
||||
onSelectionChanged: (selectedRows) {
|
||||
context.read<DeviceManagementBloc>().add(UpdateSelection(selectedRows));
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(UpdateSelection(selectedRows));
|
||||
},
|
||||
initialSelectedIds:
|
||||
context.read<DeviceManagementBloc>().selectedDevices.map((device) => device.uuid!).toList(),
|
||||
initialSelectedIds: context
|
||||
.read<DeviceManagementBloc>()
|
||||
.selectedDevices
|
||||
.map((device) => device.uuid!)
|
||||
.toList(),
|
||||
isEmpty: devicesToShow.isEmpty,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -12,8 +12,7 @@ class DeviceSearchFilters extends StatefulWidget {
|
||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||
}
|
||||
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
with HelperResponsiveLayout {
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
||||
final TextEditingController communityController = TextEditingController();
|
||||
final TextEditingController unitNameController = TextEditingController();
|
||||
final TextEditingController productNameController = TextEditingController();
|
||||
@ -27,8 +26,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Space Name", unitNameController, 200),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField(
|
||||
"Device Name / Product Name", productNameController, 300),
|
||||
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchResetButtons(),
|
||||
],
|
||||
@ -53,8 +51,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchField(
|
||||
String title, TextEditingController controller, double width) {
|
||||
Widget _buildSearchField(String title, TextEditingController controller, double width) {
|
||||
return Container(
|
||||
child: StatefulTextField(
|
||||
title: title,
|
||||
@ -88,7 +85,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
productNameController.clear();
|
||||
context.read<DeviceManagementBloc>()
|
||||
..add(ResetFilters())
|
||||
..add(FetchDevices());
|
||||
..add(FetchDevices(context));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -95,8 +95,9 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
||||
]),
|
||||
TableRow(
|
||||
children: [
|
||||
_buildInfoRow('Space Name:', device.unit?.name ?? 'N/A'),
|
||||
_buildInfoRow('Room:', device.room?.name ?? 'N/A'),
|
||||
_buildInfoRow('Space Name:',
|
||||
device.spaces?.firstOrNull?.spaceName ?? 'N/A'),
|
||||
_buildInfoRow('Room:', device.subspace?.subspaceName ?? 'N/A'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
@ -111,9 +112,13 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
||||
),
|
||||
_buildInfoRow(
|
||||
'Battery Level:',
|
||||
device.batteryLevel != null ? '${device.batteryLevel ?? 0}%' : "-",
|
||||
device.batteryLevel != null
|
||||
? '${device.batteryLevel ?? 0}%'
|
||||
: "-",
|
||||
statusColor: device.batteryLevel != null
|
||||
? (device.batteryLevel! < 20 ? ColorsManager.red : ColorsManager.green)
|
||||
? (device.batteryLevel! < 20
|
||||
? ColorsManager.red
|
||||
: ColorsManager.green)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
|
@ -1,49 +1,49 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/services/home_api.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
|
||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
final Graph graph = Graph()..isTree = true;
|
||||
final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
||||
List<Node> sourcesList = [];
|
||||
List<Node> destinationsList = [];
|
||||
// final Graph graph = Graph()..isTree = true;
|
||||
// final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
||||
// List<Node> sourcesList = [];
|
||||
// List<Node> destinationsList = [];
|
||||
UserModel? user;
|
||||
String terms = '';
|
||||
String policy = '';
|
||||
|
||||
HomeBloc() : super((HomeInitial())) {
|
||||
on<CreateNewNode>(_createNode);
|
||||
// on<CreateNewNode>(_createNode);
|
||||
on<FetchUserInfo>(_fetchUserInfo);
|
||||
on<FetchTermEvent>(_fetchTerms);
|
||||
on<FetchPolicyEvent>(_fetchPolicy);
|
||||
on<ConfirmUserAgreementEvent>(_confirmUserAgreement);
|
||||
}
|
||||
|
||||
void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
||||
emit(HomeInitial());
|
||||
sourcesList.add(event.sourceNode);
|
||||
destinationsList.add(event.destinationNode);
|
||||
for (int i = 0; i < sourcesList.length; i++) {
|
||||
graph.addEdge(sourcesList[i], destinationsList[i]);
|
||||
}
|
||||
// void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
||||
// emit(HomeInitial());
|
||||
// sourcesList.add(event.sourceNode);
|
||||
// destinationsList.add(event.destinationNode);
|
||||
// for (int i = 0; i < sourcesList.length; i++) {
|
||||
// graph.addEdge(sourcesList[i], destinationsList[i]);
|
||||
// }
|
||||
|
||||
builder
|
||||
..siblingSeparation = (100)
|
||||
..levelSeparation = (150)
|
||||
..subtreeSeparation = (150)
|
||||
..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
|
||||
emit(HomeUpdateTree(graph: graph, builder: builder));
|
||||
}
|
||||
// builder
|
||||
// ..siblingSeparation = (100)
|
||||
// ..levelSeparation = (150)
|
||||
// ..subtreeSeparation = (150)
|
||||
// ..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
|
||||
// emit(HomeUpdateTree(graph: graph, builder: builder));
|
||||
// }
|
||||
|
||||
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
|
||||
abstract class HomeEvent extends Equatable {
|
||||
const HomeEvent();
|
||||
@ -8,19 +8,21 @@ abstract class HomeEvent extends Equatable {
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class CreateNewNode extends HomeEvent {
|
||||
final Node sourceNode;
|
||||
final Node destinationNode;
|
||||
const CreateNewNode(
|
||||
{required this.sourceNode, required this.destinationNode});
|
||||
// class CreateNewNode extends HomeEvent {
|
||||
// final Node sourceNode;
|
||||
// final Node destinationNode;
|
||||
// const CreateNewNode(
|
||||
// {required this.sourceNode, required this.destinationNode});
|
||||
|
||||
@override
|
||||
List<Object> get props => [sourceNode, destinationNode];
|
||||
}
|
||||
// @override
|
||||
// List<Object> get props => [sourceNode, destinationNode];
|
||||
// }
|
||||
|
||||
class FetchUserInfo extends HomeEvent {
|
||||
const FetchUserInfo();
|
||||
}class FetchTermEvent extends HomeEvent {}
|
||||
}
|
||||
|
||||
class FetchTermEvent extends HomeEvent {}
|
||||
|
||||
class FetchPolicyEvent extends HomeEvent {}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
|
||||
abstract class HomeState extends Equatable {
|
||||
const HomeState();
|
||||
@ -7,26 +7,26 @@ abstract class HomeState extends Equatable {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class LoadingHome extends HomeState {}
|
||||
|
||||
class HomeInitial extends HomeState {}
|
||||
|
||||
class TermsAgreement extends HomeState {}
|
||||
|
||||
class PolicyAgreement extends HomeState {}
|
||||
|
||||
class HomeCounterState extends HomeState {
|
||||
final int counter;
|
||||
const HomeCounterState(this.counter);
|
||||
}
|
||||
// class HomeCounterState extends HomeState {
|
||||
// final int counter;
|
||||
// const HomeCounterState(this.counter);
|
||||
// }
|
||||
|
||||
class HomeUpdateTree extends HomeState {
|
||||
final Graph graph;
|
||||
final BuchheimWalkerConfiguration builder;
|
||||
// class HomeUpdateTree extends HomeState {
|
||||
// final Graph graph;
|
||||
// final BuchheimWalkerConfiguration builder;
|
||||
|
||||
const HomeUpdateTree({required this.graph, required this.builder});
|
||||
// const HomeUpdateTree({required this.graph, required this.builder});
|
||||
|
||||
@override
|
||||
List<Object> get props => [graph, builder];
|
||||
}
|
||||
|
||||
//FetchTermEvent
|
||||
// @override
|
||||
// List<Object> get props => [graph, builder];
|
||||
// }
|
||||
|
@ -41,8 +41,7 @@ class HomeMobilePage extends StatelessWidget {
|
||||
SizedBox(height: size.height * 0.05),
|
||||
const Text(
|
||||
'ACCESS YOUR APPS',
|
||||
style:
|
||||
TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Expanded(
|
||||
@ -51,9 +50,8 @@ class HomeMobilePage extends StatelessWidget {
|
||||
height: size.height * 0.6,
|
||||
width: size.width * 0.68,
|
||||
child: GridView.builder(
|
||||
itemCount: 8,
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
itemCount: 3,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 20.0,
|
||||
mainAxisSpacing: 20.0,
|
||||
@ -65,8 +63,7 @@ class HomeMobilePage extends StatelessWidget {
|
||||
active: homeItems[index]['active'],
|
||||
name: homeItems[index]['title'],
|
||||
img: homeItems[index]['icon'],
|
||||
onTap: () =>
|
||||
homeBloc.homeItems[index].onPress(context),
|
||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -97,33 +94,33 @@ class HomeMobilePage extends StatelessWidget {
|
||||
'icon': Assets.devicesIcon,
|
||||
'active': true,
|
||||
},
|
||||
{
|
||||
'title': 'Move in',
|
||||
'icon': Assets.moveinIcon,
|
||||
'active': false,
|
||||
},
|
||||
{
|
||||
'title': 'Construction',
|
||||
'icon': Assets.constructionIcon,
|
||||
'active': false,
|
||||
},
|
||||
{
|
||||
'title': 'Energy',
|
||||
'icon': Assets.energyIcon,
|
||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
'active': false,
|
||||
},
|
||||
{
|
||||
'title': 'Integrations',
|
||||
'icon': Assets.integrationsIcon,
|
||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
'active': false,
|
||||
},
|
||||
{
|
||||
'title': 'Asset',
|
||||
'icon': Assets.assetIcon,
|
||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
'active': false,
|
||||
},
|
||||
// {
|
||||
// 'title': 'Move in',
|
||||
// 'icon': Assets.moveinIcon,
|
||||
// 'active': false,
|
||||
// },
|
||||
// {
|
||||
// 'title': 'Construction',
|
||||
// 'icon': Assets.constructionIcon,
|
||||
// 'active': false,
|
||||
// },
|
||||
// {
|
||||
// 'title': 'Energy',
|
||||
// 'icon': Assets.energyIcon,
|
||||
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
// 'active': false,
|
||||
// },
|
||||
// {
|
||||
// 'title': 'Integrations',
|
||||
// 'icon': Assets.integrationsIcon,
|
||||
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
// 'active': false,
|
||||
// },
|
||||
// {
|
||||
// 'title': 'Asset',
|
||||
// 'icon': Assets.assetIcon,
|
||||
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
// 'active': false,
|
||||
// },
|
||||
];
|
||||
}
|
||||
|
@ -58,7 +58,10 @@ class HomeWebPage extends StatelessWidget {
|
||||
scaffoldBody: SizedBox(
|
||||
height: size.height,
|
||||
width: size.width,
|
||||
child: Column(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
@ -78,9 +81,8 @@ class HomeWebPage extends StatelessWidget {
|
||||
width: size.width * 0.68,
|
||||
child: GridView.builder(
|
||||
itemCount: 3, //8
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3, //4
|
||||
crossAxisSpacing: 20.0,
|
||||
mainAxisSpacing: 20.0,
|
||||
childAspectRatio: 1.5,
|
||||
@ -91,8 +93,7 @@ class HomeWebPage extends StatelessWidget {
|
||||
active: homeBloc.homeItems[index].active!,
|
||||
name: homeBloc.homeItems[index].title!,
|
||||
img: homeBloc.homeItems[index].icon!,
|
||||
onTap: () =>
|
||||
homeBloc.homeItems[index].onPress(context),
|
||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -100,6 +101,8 @@ class HomeWebPage extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -1,185 +1,185 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
// import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
// import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
// import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
|
||||
class TreeWidget extends StatelessWidget {
|
||||
const TreeWidget({super.key});
|
||||
// class TreeWidget extends StatelessWidget {
|
||||
// const TreeWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// final HomeBloc homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
String firstNodeName = '';
|
||||
String secondNodeName = '';
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// // final HomeBloc homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
// String firstNodeName = '';
|
||||
// String secondNodeName = '';
|
||||
|
||||
return SafeArea(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
||||
if (state is HomeInitial) {
|
||||
return Wrap(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Subtree separation"),
|
||||
onChanged: (text) {
|
||||
firstNodeName = text;
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Container(
|
||||
width: 100,
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(labelText: "Node Name"),
|
||||
onChanged: (text) {
|
||||
secondNodeName = text;
|
||||
},
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
final node1 = Node.Id(firstNodeName);
|
||||
final node2 = Node.Id(secondNodeName);
|
||||
context.read<HomeBloc>().add(CreateNewNode(
|
||||
sourceNode: node1, destinationNode: node2));
|
||||
},
|
||||
child: Text("Add"),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
if (state is HomeUpdateTree) {
|
||||
return Expanded(
|
||||
child: InteractiveViewer(
|
||||
constrained: false,
|
||||
boundaryMargin: const EdgeInsets.all(100),
|
||||
minScale: 0.01,
|
||||
maxScale: 5.6,
|
||||
child: GraphView(
|
||||
graph: state.graph,
|
||||
algorithm: BuchheimWalkerAlgorithm(
|
||||
state.builder, TreeEdgeRenderer(state.builder)),
|
||||
paint: Paint()
|
||||
..color = Colors.green
|
||||
..strokeWidth = 1
|
||||
..style = PaintingStyle.stroke,
|
||||
builder: (Node node) {
|
||||
// I can decide what widget should be shown here based on the id
|
||||
var nodeName = node.key!.value;
|
||||
return rectangleWidget(nodeName, node, context);
|
||||
},
|
||||
)),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// return SafeArea(
|
||||
// child: Container(
|
||||
// padding: const EdgeInsets.all(24),
|
||||
// width: MediaQuery.sizeOf(context).width,
|
||||
// height: MediaQuery.sizeOf(context).height,
|
||||
// alignment: AlignmentDirectional.center,
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
||||
// if (state is HomeInitial) {
|
||||
// return Wrap(
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: 100,
|
||||
// child: TextFormField(
|
||||
// decoration: const InputDecoration(
|
||||
// labelText: "Subtree separation"),
|
||||
// onChanged: (text) {
|
||||
// firstNodeName = text;
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// width: 8,
|
||||
// ),
|
||||
// Container(
|
||||
// width: 100,
|
||||
// child: TextFormField(
|
||||
// decoration: InputDecoration(labelText: "Node Name"),
|
||||
// onChanged: (text) {
|
||||
// secondNodeName = text;
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// onPressed: () {
|
||||
// final node1 = Node.Id(firstNodeName);
|
||||
// final node2 = Node.Id(secondNodeName);
|
||||
// context.read<HomeBloc>().add(CreateNewNode(
|
||||
// sourceNode: node1, destinationNode: node2));
|
||||
// },
|
||||
// child: Text("Add"),
|
||||
// )
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
// if (state is HomeUpdateTree) {
|
||||
// return Expanded(
|
||||
// child: InteractiveViewer(
|
||||
// constrained: false,
|
||||
// boundaryMargin: const EdgeInsets.all(100),
|
||||
// minScale: 0.01,
|
||||
// maxScale: 5.6,
|
||||
// child: GraphView(
|
||||
// graph: state.graph,
|
||||
// algorithm: BuchheimWalkerAlgorithm(
|
||||
// state.builder, TreeEdgeRenderer(state.builder)),
|
||||
// paint: Paint()
|
||||
// ..color = Colors.green
|
||||
// ..strokeWidth = 1
|
||||
// ..style = PaintingStyle.stroke,
|
||||
// builder: (Node node) {
|
||||
// // I can decide what widget should be shown here based on the id
|
||||
// var nodeName = node.key!.value;
|
||||
// return rectangleWidget(nodeName, node, context);
|
||||
// },
|
||||
// )),
|
||||
// );
|
||||
// } else {
|
||||
// return Container();
|
||||
// }
|
||||
// })
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
|
||||
String nodeName = '';
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: blocContext,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Add a child'),
|
||||
content: TextField(
|
||||
decoration:
|
||||
const InputDecoration(hintText: 'Enter your text here'),
|
||||
onChanged: (value) {
|
||||
nodeName = value;
|
||||
},
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text('Close'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (nodeName.isNotEmpty) {
|
||||
final newNode = Node.Id(nodeName);
|
||||
blocContext.read<HomeBloc>().add(CreateNewNode(
|
||||
sourceNode: node, destinationNode: newNode));
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text('Add'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: MediaQuery.of(blocContext).size.width * 0.2,
|
||||
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||
padding: EdgeInsets.all(20.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 3), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
child: Icon(
|
||||
Icons.location_on,
|
||||
color: Colors.blue,
|
||||
size: 40.0,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10.0),
|
||||
SizedBox(
|
||||
child: Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
fontSize: 24.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Container(
|
||||
child: const Icon(
|
||||
Icons.add_circle_outline,
|
||||
color: Colors.grey,
|
||||
size: 24.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
// Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
|
||||
// String nodeName = '';
|
||||
// return InkWell(
|
||||
// onTap: () {
|
||||
// showDialog(
|
||||
// context: blocContext,
|
||||
// builder: (BuildContext context) {
|
||||
// return AlertDialog(
|
||||
// title: const Text('Add a child'),
|
||||
// content: TextField(
|
||||
// decoration:
|
||||
// const InputDecoration(hintText: 'Enter your text here'),
|
||||
// onChanged: (value) {
|
||||
// nodeName = value;
|
||||
// },
|
||||
// ),
|
||||
// actions: <Widget>[
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// child: Text('Close'),
|
||||
// ),
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// if (nodeName.isNotEmpty) {
|
||||
// final newNode = Node.Id(nodeName);
|
||||
// blocContext.read<HomeBloc>().add(CreateNewNode(
|
||||
// sourceNode: node, destinationNode: newNode));
|
||||
// }
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// child: Text('Add'),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// },
|
||||
// child: Container(
|
||||
// width: MediaQuery.of(blocContext).size.width * 0.2,
|
||||
// margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||
// padding: EdgeInsets.all(20.0),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(10.0),
|
||||
// boxShadow: [
|
||||
// BoxShadow(
|
||||
// color: Colors.grey.withOpacity(0.5),
|
||||
// spreadRadius: 2,
|
||||
// blurRadius: 5,
|
||||
// offset: Offset(0, 3), // changes position of shadow
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// const SizedBox(
|
||||
// child: Icon(
|
||||
// Icons.location_on,
|
||||
// color: Colors.blue,
|
||||
// size: 40.0,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 10.0),
|
||||
// SizedBox(
|
||||
// child: Text(
|
||||
// text,
|
||||
// style: const TextStyle(
|
||||
// fontSize: 24.0,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const Spacer(),
|
||||
// Container(
|
||||
// child: const Icon(
|
||||
// Icons.add_circle_outline,
|
||||
// color: Colors.grey,
|
||||
// size: 24.0,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
@ -1,85 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/ac_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/one_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/three_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/two_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
|
||||
class DeviceDialogHelper {
|
||||
static Future<Map<String, dynamic>?> showDeviceDialog(
|
||||
BuildContext context,
|
||||
Map<String, dynamic> data, {
|
||||
required bool removeComparetors,
|
||||
}) async {
|
||||
final functions = data['functions'] as List<DeviceFunction>;
|
||||
|
||||
try {
|
||||
final result = await _getDialogForDeviceType(
|
||||
context,
|
||||
data['productType'],
|
||||
data,
|
||||
functions,
|
||||
removeComparetors: removeComparetors,
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>?> _getDialogForDeviceType(
|
||||
BuildContext context,
|
||||
String productType,
|
||||
Map<String, dynamic> data,
|
||||
List<DeviceFunction> functions,
|
||||
{required bool removeComparetors}) async {
|
||||
final routineBloc = context.read<RoutineBloc>();
|
||||
final deviceSelectedFunctions =
|
||||
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
|
||||
|
||||
switch (productType) {
|
||||
case 'AC':
|
||||
return ACHelper.showACFunctionsDialog(
|
||||
context,
|
||||
functions,
|
||||
data['device'],
|
||||
deviceSelectedFunctions,
|
||||
data['uniqueCustomId'],
|
||||
removeComparetors);
|
||||
|
||||
case '1G':
|
||||
return OneGangSwitchHelper.showSwitchFunctionsDialog(
|
||||
context,
|
||||
functions,
|
||||
data['device'],
|
||||
deviceSelectedFunctions,
|
||||
data['uniqueCustomId'],
|
||||
removeComparetors);
|
||||
case '2G':
|
||||
return TwoGangSwitchHelper.showSwitchFunctionsDialog(
|
||||
context,
|
||||
functions,
|
||||
data['device'],
|
||||
deviceSelectedFunctions,
|
||||
data['uniqueCustomId'],
|
||||
removeComparetors);
|
||||
case '3G':
|
||||
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
|
||||
context,
|
||||
functions,
|
||||
data['device'],
|
||||
deviceSelectedFunctions,
|
||||
data['uniqueCustomId'],
|
||||
removeComparetors);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class RoutinesView extends StatefulWidget {
|
||||
const RoutinesView({super.key});
|
||||
|
||||
@override
|
||||
State<RoutinesView> createState() => _RoutinesViewState();
|
||||
}
|
||||
|
||||
class _RoutinesViewState extends State<RoutinesView> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
builder: (context, state) {
|
||||
if (state.createRoutineView) {
|
||||
return const CreateNewRoutineView();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Create New Routines",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
RoutineViewCard(
|
||||
onTap: () {
|
||||
context.read<RoutineBloc>().add(
|
||||
(ResetRoutineState()),
|
||||
);
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
},
|
||||
icon: Icons.add,
|
||||
textString: '',
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Expanded(child: FetchRoutineScenesAutomation()),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.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 FetchRoutineScenesAutomation extends StatefulWidget {
|
||||
const FetchRoutineScenesAutomation({super.key});
|
||||
|
||||
@override
|
||||
State<FetchRoutineScenesAutomation> createState() => _FetchRoutineScenesState();
|
||||
}
|
||||
|
||||
class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
|
||||
with HelperResponsiveLayout {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>()
|
||||
..add(const LoadScenes(spaceId, communityId))
|
||||
..add(const LoadAutomation(spaceId));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
builder: (context, state) {
|
||||
return state.isLoading
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Scenes (Tab to Run)",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
if (state.scenes.isEmpty)
|
||||
Text(
|
||||
"No scenes found",
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
if (state.scenes.isNotEmpty)
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: isSmallScreenSize(context) ? 160 : 170,
|
||||
),
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: state.scenes.length,
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
||||
),
|
||||
child: RoutineViewCard(
|
||||
onTap: () {
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
context.read<RoutineBloc>().add(
|
||||
GetSceneDetails(
|
||||
sceneId: state.scenes[index].id,
|
||||
isTabToRun: true,
|
||||
isUpdate: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
textString: state.scenes[index].name,
|
||||
icon: state.scenes[index].icon ?? Assets.logoHorizontal,
|
||||
isFromScenes: true,
|
||||
iconInBytes: state.scenes[index].iconInBytes,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"Automations",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
if (state.automations.isEmpty)
|
||||
Text(
|
||||
"No automations found",
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
if (state.automations.isNotEmpty)
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: isSmallScreenSize(context) ? 160 : 170,
|
||||
),
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: state.automations.length,
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
||||
),
|
||||
child: RoutineViewCard(
|
||||
onTap: () {
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
context.read<RoutineBloc>().add(
|
||||
GetAutomationDetails(
|
||||
automationId: state.automations[index].id,
|
||||
isAutomation: true,
|
||||
isUpdate: true),
|
||||
);
|
||||
},
|
||||
textString: state.automations[index].name,
|
||||
icon: state.automations[index].icon ?? Assets.automation,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
|
||||
class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
@ -1,5 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
|
||||
abstract class EffectPeriodEvent extends Equatable {
|
@ -2,7 +2,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
|
||||
part 'functions_bloc_event.dart';
|
||||
part 'functions_bloc_state.dart';
|
||||
@ -26,8 +26,7 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
||||
functionCode: event.functionData.functionCode,
|
||||
operationName: event.functionData.operationName,
|
||||
value: event.functionData.value ?? existingData.value,
|
||||
valueDescription: event.functionData.valueDescription ??
|
||||
existingData.valueDescription,
|
||||
valueDescription: event.functionData.valueDescription ?? existingData.valueDescription,
|
||||
condition: event.functionData.condition ?? existingData.condition,
|
||||
);
|
||||
} else {
|
||||
@ -59,10 +58,8 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _onSelectFunction(
|
||||
SelectFunction event, Emitter<FunctionBlocState> emit) {
|
||||
FutureOr<void> _onSelectFunction(SelectFunction event, Emitter<FunctionBlocState> emit) {
|
||||
emit(state.copyWith(
|
||||
selectedFunction: event.functionCode,
|
||||
selectedOperationName: event.operationName));
|
||||
selectedFunction: event.functionCode, selectedOperationName: event.operationName));
|
||||
}
|
||||
}
|
@ -4,12 +4,12 @@ import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.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/delay/delay_fucntions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.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/pages/routines/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/delay/delay_fucntions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/routine_details_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/routine_model.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
import 'package:syncrow_web/services/routines_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
@ -19,8 +19,8 @@ import 'package:uuid/uuid.dart';
|
||||
part 'routine_event.dart';
|
||||
part 'routine_state.dart';
|
||||
|
||||
const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
const communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||
String spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
String communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||
|
||||
class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
RoutineBloc() : super(const RoutineState()) {
|
||||
@ -57,8 +57,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
emit(state.copyWith(routineTab: event.isRoutineTab, createRoutineView: false));
|
||||
add(ResetRoutineState());
|
||||
if (event.isRoutineTab) {
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,7 +156,14 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
try {
|
||||
final scenes = await SceneApi.getScenesByUnitId(event.unitId, event.communityId);
|
||||
spaceId = event.spaceId;
|
||||
communityId = event.communityId;
|
||||
|
||||
List<ScenesModel> scenes = [];
|
||||
|
||||
if (communityId.isNotEmpty && spaceId.isNotEmpty) {
|
||||
scenes = await SceneApi.getScenes(event.spaceId, event.communityId);
|
||||
}
|
||||
emit(state.copyWith(
|
||||
scenes: scenes,
|
||||
isLoading: false,
|
||||
@ -167,7 +174,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
loadScenesErrorMessage: 'Failed to load scenes',
|
||||
errorMessage: '',
|
||||
loadAutomationErrorMessage: '',
|
||||
));
|
||||
scenes: []));
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,27 +182,22 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
try {
|
||||
final automations = await SceneApi.getAutomationByUnitId(event.unitId);
|
||||
if (automations.isNotEmpty) {
|
||||
spaceId = event.spaceId;
|
||||
List<ScenesModel> automations = [];
|
||||
if (spaceId.isNotEmpty) {
|
||||
automations = await SceneApi.getAutomation(event.spaceId);
|
||||
}
|
||||
emit(state.copyWith(
|
||||
automations: automations,
|
||||
isLoading: false,
|
||||
));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
loadAutomationErrorMessage: 'Failed to load automations',
|
||||
errorMessage: '',
|
||||
loadScenesErrorMessage: '',
|
||||
));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
loadAutomationErrorMessage: 'Failed to load automations',
|
||||
errorMessage: '',
|
||||
loadScenesErrorMessage: '',
|
||||
));
|
||||
automations: []));
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,8 +292,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final result = await SceneApi.createScene(createSceneModel);
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -419,8 +421,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final result = await SceneApi.createAutomation(createAutomationModel);
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -785,8 +787,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
SceneApi.deleteAutomation(unitUuid: spaceId, automationId: state.automationId ?? '');
|
||||
}
|
||||
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(ResetRoutineState());
|
||||
emit(state.copyWith(isLoading: false, createRoutineView: false));
|
||||
} catch (e) {
|
||||
@ -814,7 +816,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
FutureOr<void> _fetchDevices(FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
try {
|
||||
final devices = await DevicesManagementApi().fetchDevices();
|
||||
final devices = await DevicesManagementApi().fetchDevices('', '');
|
||||
|
||||
emit(state.copyWith(isLoading: false, devices: devices));
|
||||
} catch (e) {
|
||||
@ -892,8 +894,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -1021,8 +1023,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
@ -27,22 +27,22 @@ class AddToThenContainer extends RoutineEvent {
|
||||
}
|
||||
|
||||
class LoadScenes extends RoutineEvent {
|
||||
final String unitId;
|
||||
final String spaceId;
|
||||
final String communityId;
|
||||
|
||||
const LoadScenes(this.unitId, this.communityId);
|
||||
const LoadScenes(this.spaceId, this.communityId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [unitId, communityId];
|
||||
List<Object> get props => [spaceId, communityId];
|
||||
}
|
||||
|
||||
class LoadAutomation extends RoutineEvent {
|
||||
final String unitId;
|
||||
final String spaceId;
|
||||
|
||||
const LoadAutomation(this.unitId);
|
||||
const LoadAutomation(this.spaceId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [unitId];
|
||||
List<Object> get props => [spaceId];
|
||||
}
|
||||
|
||||
class AddFunctionToRoutine extends RoutineEvent {
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_state.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_state.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/icon_model.dart';
|
||||
import 'package:syncrow_web/services/routines_api.dart';
|
||||
|
||||
class SettingBloc extends Bloc<SettingEvent, SettingState> {
|
@ -1,5 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/icon_model.dart';
|
||||
|
||||
abstract class SettingState extends Equatable {
|
||||
const SettingState();
|
@ -0,0 +1,62 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ac_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/three_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/two_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
|
||||
class DeviceDialogHelper {
|
||||
static Future<Map<String, dynamic>?> showDeviceDialog(
|
||||
BuildContext context,
|
||||
Map<String, dynamic> data, {
|
||||
required bool removeComparetors,
|
||||
}) async {
|
||||
final functions = data['functions'] as List<DeviceFunction>;
|
||||
|
||||
try {
|
||||
final result = await _getDialogForDeviceType(
|
||||
context,
|
||||
data['productType'],
|
||||
data,
|
||||
functions,
|
||||
removeComparetors: removeComparetors,
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>?> _getDialogForDeviceType(BuildContext context,
|
||||
String productType, Map<String, dynamic> data, List<DeviceFunction> functions,
|
||||
{required bool removeComparetors}) async {
|
||||
final routineBloc = context.read<RoutineBloc>();
|
||||
final deviceSelectedFunctions =
|
||||
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
|
||||
|
||||
switch (productType) {
|
||||
case 'AC':
|
||||
return ACHelper.showACFunctionsDialog(context, functions, data['device'],
|
||||
deviceSelectedFunctions, data['uniqueCustomId'], removeComparetors);
|
||||
|
||||
case '1G':
|
||||
return OneGangSwitchHelper.showSwitchFunctionsDialog(context, functions, data['device'],
|
||||
deviceSelectedFunctions, data['uniqueCustomId'], removeComparetors);
|
||||
case '2G':
|
||||
return TwoGangSwitchHelper.showSwitchFunctionsDialog(context, functions, data['device'],
|
||||
deviceSelectedFunctions, data['uniqueCustomId'], removeComparetors);
|
||||
case '3G':
|
||||
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(context, functions, data['device'],
|
||||
deviceSelectedFunctions, data['uniqueCustomId'], removeComparetors);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,9 +3,9 @@ import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.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';
|
@ -1,6 +1,6 @@
|
||||
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ac/ac_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class DelayFunction extends BaseSwitchFunction {
|
@ -1,5 +1,5 @@
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
|
||||
abstract class BaseSwitchFunction extends DeviceFunction<bool> {
|
||||
BaseSwitchFunction({
|
@ -1,5 +1,5 @@
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class OneGangSwitchFunction extends BaseSwitchFunction {
|
@ -1,5 +1,5 @@
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class ThreeGangSwitch1Function extends BaseSwitchFunction {
|
||||
@ -26,8 +26,7 @@ class ThreeGangSwitch1Function extends BaseSwitchFunction {
|
||||
}
|
||||
|
||||
class ThreeGangCountdown1Function extends BaseSwitchFunction {
|
||||
ThreeGangCountdown1Function(
|
||||
{required super.deviceId, required super.deviceName})
|
||||
ThreeGangCountdown1Function({required super.deviceId, required super.deviceName})
|
||||
: super(
|
||||
code: 'countdown_1',
|
||||
operationName: 'Light 1 Countdown',
|
||||
@ -71,8 +70,7 @@ class ThreeGangSwitch2Function extends BaseSwitchFunction {
|
||||
}
|
||||
|
||||
class ThreeGangCountdown2Function extends BaseSwitchFunction {
|
||||
ThreeGangCountdown2Function(
|
||||
{required super.deviceId, required super.deviceName})
|
||||
ThreeGangCountdown2Function({required super.deviceId, required super.deviceName})
|
||||
: super(
|
||||
code: 'countdown_2',
|
||||
operationName: 'Light 2 Countdown',
|
||||
@ -116,8 +114,7 @@ class ThreeGangSwitch3Function extends BaseSwitchFunction {
|
||||
}
|
||||
|
||||
class ThreeGangCountdown3Function extends BaseSwitchFunction {
|
||||
ThreeGangCountdown3Function(
|
||||
{required super.deviceId, required super.deviceName})
|
||||
ThreeGangCountdown3Function({required super.deviceId, required super.deviceName})
|
||||
: super(
|
||||
code: 'countdown_3',
|
||||
operationName: 'Light 3 Countdown',
|
@ -1,5 +1,5 @@
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class TwoGangSwitch1Function extends BaseSwitchFunction {
|
||||
@ -49,8 +49,7 @@ class TwoGangSwitch2Function extends BaseSwitchFunction {
|
||||
}
|
||||
|
||||
class TwoGangCountdown1Function extends BaseSwitchFunction {
|
||||
TwoGangCountdown1Function(
|
||||
{required super.deviceId, required super.deviceName})
|
||||
TwoGangCountdown1Function({required super.deviceId, required super.deviceName})
|
||||
: super(
|
||||
code: 'countdown_1',
|
||||
operationName: 'Light 1 Countdown',
|
||||
@ -71,8 +70,7 @@ class TwoGangCountdown1Function extends BaseSwitchFunction {
|
||||
}
|
||||
|
||||
class TwoGangCountdown2Function extends BaseSwitchFunction {
|
||||
TwoGangCountdown2Function(
|
||||
{required super.deviceId, required super.deviceName})
|
||||
TwoGangCountdown2Function({required super.deviceId, required super.deviceName})
|
||||
: super(
|
||||
code: 'countdown_2',
|
||||
operationName: 'Light 2 Countdown',
|
@ -1,7 +1,7 @@
|
||||
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';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||
|
||||
class RoutineDetailsModel {
|
||||
final String spaceUuid;
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/conditions_routines_devices_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/if_container.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_search_and_buttons.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/then_container.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/conditions_routines_devices_view.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/if_container.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_search_and_buttons.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/then_container.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class CreateNewRoutineView extends StatelessWidget {
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/effictive_period_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/period_option.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/repeat_days.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/effictive_period_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/period_option.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/repeat_days.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class EffectivePeriodView extends StatelessWidget {
|
91
lib/pages/routines/view/routines_view.dart
Normal file
91
lib/pages/routines/view/routines_view.dart
Normal file
@ -0,0 +1,91 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/view/create_new_routine_view.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/main_routine_view/routine_view_card.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
class RoutinesView extends StatefulWidget {
|
||||
const RoutinesView({super.key});
|
||||
|
||||
@override
|
||||
State<RoutinesView> createState() => _RoutinesViewState();
|
||||
}
|
||||
|
||||
class _RoutinesViewState extends State<RoutinesView> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
builder: (context, state) {
|
||||
if (state.createRoutineView) {
|
||||
return const CreateNewRoutineView();
|
||||
}
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SpaceTreeView(
|
||||
onSelect: () {},
|
||||
)),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: ListView(children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Create New Routines",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
RoutineViewCard(
|
||||
onTap: () {
|
||||
if (context.read<SpaceTreeBloc>().selectedCommunityId.isNotEmpty &&
|
||||
context.read<SpaceTreeBloc>().selectedSpaceId.isNotEmpty) {
|
||||
context.read<RoutineBloc>().add(
|
||||
(ResetRoutineState()),
|
||||
);
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
} else {
|
||||
CustomSnackBar.redSnackBar('Please select a space');
|
||||
}
|
||||
},
|
||||
icon: Icons.add,
|
||||
textString: '',
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Expanded(child: FetchRoutineScenesAutomation()),
|
||||
],
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_devices.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routines_title_widget.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/scenes_and_automations.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/search_bar_condition_title.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_devices.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routines_title_widget.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/scenes_and_automations.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/search_bar_condition_title.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class ConditionsRoutinesDevicesView extends StatelessWidget {
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/custom_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class DeleteSceneWidget extends StatelessWidget {
|
@ -3,8 +3,8 @@ import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/helper/dialog_helper/device_dialog_helper.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/helper/dialog_helper/device_dialog_helper.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dragable_card.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';
|
||||
@ -26,9 +26,7 @@ class IfContainer extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text('IF',
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
const Text('IF', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
if (state.isAutomation && state.ifItems.isNotEmpty)
|
||||
AutomationOperatorSelector(
|
||||
selectedOperator: state.selectedAutomationOperator),
|
||||
@ -55,44 +53,34 @@ class IfContainer extends StatelessWidget {
|
||||
(index) => GestureDetector(
|
||||
onTap: () async {
|
||||
if (!state.isTabToRun) {
|
||||
final result = await DeviceDialogHelper
|
||||
.showDeviceDialog(
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||
context, state.ifItems[index],
|
||||
removeComparetors: false);
|
||||
|
||||
if (result != null) {
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToIfContainer(
|
||||
state.ifItems[index], false));
|
||||
} else if (![
|
||||
'AC',
|
||||
'1G',
|
||||
'2G',
|
||||
'3G'
|
||||
].contains(
|
||||
state.ifItems[index]['productType'])) {
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToIfContainer(
|
||||
state.ifItems[index], false));
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(state.ifItems[index], false));
|
||||
} else if (!['AC', '1G', '2G', '3G']
|
||||
.contains(state.ifItems[index]['productType'])) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(state.ifItems[index], false));
|
||||
}
|
||||
}
|
||||
},
|
||||
child: DraggableCard(
|
||||
imagePath:
|
||||
state.ifItems[index]['imagePath'] ?? '',
|
||||
imagePath: state.ifItems[index]['imagePath'] ?? '',
|
||||
title: state.ifItems[index]['title'] ?? '',
|
||||
deviceData: state.ifItems[index],
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
|
||||
isFromThen: false,
|
||||
isFromIf: true,
|
||||
onRemove: () {
|
||||
context.read<RoutineBloc>().add(
|
||||
RemoveDragCard(
|
||||
context.read<RoutineBloc>().add(RemoveDragCard(
|
||||
index: index,
|
||||
isFromThen: false,
|
||||
key: state.ifItems[index]
|
||||
['uniqueCustomId']));
|
||||
key: state.ifItems[index]['uniqueCustomId']));
|
||||
},
|
||||
),
|
||||
)),
|
||||
@ -113,23 +101,15 @@ class IfContainer extends StatelessWidget {
|
||||
|
||||
if (!state.isTabToRun) {
|
||||
if (mutableData['deviceId'] == 'tab_to_run') {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, true));
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, true));
|
||||
} else {
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||
context, mutableData,
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData,
|
||||
removeComparetors: false);
|
||||
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, false));
|
||||
} else if (!['AC', '1G', '2G', '3G']
|
||||
.contains(mutableData['productType'])) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, false));
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||
} else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) {
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,9 +155,7 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'or'));
|
||||
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'or'));
|
||||
},
|
||||
),
|
||||
Container(
|
||||
@ -203,9 +181,7 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'and'));
|
||||
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'and'));
|
||||
},
|
||||
),
|
||||
],
|
@ -0,0 +1,143 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/main_routine_view/routine_view_card.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class FetchRoutineScenesAutomation extends StatefulWidget {
|
||||
const FetchRoutineScenesAutomation({super.key});
|
||||
|
||||
@override
|
||||
State<FetchRoutineScenesAutomation> createState() => _FetchRoutineScenesState();
|
||||
}
|
||||
|
||||
class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
|
||||
with HelperResponsiveLayout {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>()
|
||||
..add(LoadScenes(context.read<SpaceTreeBloc>().selectedSpaceId,
|
||||
context.read<SpaceTreeBloc>().selectedCommunityId))
|
||||
..add(LoadAutomation(context.read<SpaceTreeBloc>().selectedSpaceId));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
builder: (context, state) {
|
||||
return state.isLoading
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Scenes (Tab to Run)",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
if (state.scenes.isEmpty)
|
||||
Text(
|
||||
"No scenes found",
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
if (state.scenes.isNotEmpty)
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: isSmallScreenSize(context) ? 160 : 170,
|
||||
maxWidth: MediaQuery.sizeOf(context).width * 0.7),
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: state.scenes.length,
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
||||
),
|
||||
child: RoutineViewCard(
|
||||
onTap: () {
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
context.read<RoutineBloc>().add(
|
||||
GetSceneDetails(
|
||||
sceneId: state.scenes[index].id,
|
||||
isTabToRun: true,
|
||||
isUpdate: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
textString: state.scenes[index].name,
|
||||
icon: state.scenes[index].icon ?? Assets.logoHorizontal,
|
||||
isFromScenes: true,
|
||||
iconInBytes: state.scenes[index].iconInBytes,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"Automations",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
if (state.automations.isEmpty)
|
||||
Text(
|
||||
"No automations found",
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
if (state.automations.isNotEmpty)
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: isSmallScreenSize(context) ? 160 : 170,
|
||||
maxWidth: MediaQuery.sizeOf(context).width * 0.7),
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: state.automations.length,
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
||||
),
|
||||
child: RoutineViewCard(
|
||||
onTap: () {
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
context.read<RoutineBloc>().add(
|
||||
GetAutomationDetails(
|
||||
automationId: state.automations[index].id,
|
||||
isAutomation: true,
|
||||
isUpdate: true),
|
||||
);
|
||||
},
|
||||
textString: state.automations[index].name,
|
||||
icon: state.automations[index].icon ?? Assets.automation,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -70,15 +70,13 @@ class RoutineViewCard extends StatelessWidget with HelperResponsiveLayout {
|
||||
height: iconSize,
|
||||
width: iconSize,
|
||||
child: (isFromScenes ?? false)
|
||||
? (iconInBytes != null &&
|
||||
iconInBytes?.isNotEmpty == true)
|
||||
? (iconInBytes != null && iconInBytes?.isNotEmpty == true)
|
||||
? Image.memory(
|
||||
iconInBytes!,
|
||||
height: iconSize,
|
||||
width: iconSize,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) =>
|
||||
Image.asset(
|
||||
errorBuilder: (context, error, stackTrace) => Image.asset(
|
||||
Assets.logo,
|
||||
height: iconSize,
|
||||
width: iconSize,
|
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/effictive_period_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/effictive_period_dialog.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class RepeatDays extends StatelessWidget {
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||
|
||||
class RoutineDevices extends StatelessWidget {
|
||||
const RoutineDevices({super.key});
|
||||
@ -35,9 +35,7 @@ class RoutineDevices extends StatelessWidget {
|
||||
children: deviceList.asMap().entries.map((entry) {
|
||||
final device = entry.value;
|
||||
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
||||
return device.name!
|
||||
.toLowerCase()
|
||||
.contains(state.searchText!.toLowerCase())
|
||||
return device.name!.toLowerCase().contains(state.searchText!.toLowerCase())
|
||||
? DraggableCard(
|
||||
imagePath: device.getDefaultIcon(device.productType),
|
||||
title: device.name ?? '',
|
@ -1,16 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ac/ac_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
|
||||
class ACHelper {
|
||||
static Future<Map<String, dynamic>?> showACFunctionsDialog(
|
||||
@ -27,16 +27,15 @@ class ACHelper {
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => FunctionBloc()
|
||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
child: AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||
builder: (context, state) {
|
||||
final selectedFunction = state.selectedFunction;
|
||||
final selectedOperationName = state.selectedOperationName;
|
||||
final selectedFunctionData = state.addedFunctions
|
||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
final selectedFunctionData =
|
||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
orElse: () => DeviceFunctionData(
|
||||
entityId: '',
|
||||
functionCode: selectedFunction ?? '',
|
||||
@ -66,10 +65,8 @@ class ACHelper {
|
||||
child: _buildFunctionsList(
|
||||
context: context,
|
||||
acFunctions: acFunctions,
|
||||
onFunctionSelected:
|
||||
(functionCode, operationName) => context
|
||||
.read<FunctionBloc>()
|
||||
.add(SelectFunction(
|
||||
onFunctionSelected: (functionCode, operationName) =>
|
||||
context.read<FunctionBloc>().add(SelectFunction(
|
||||
functionCode: functionCode,
|
||||
operationName: operationName,
|
||||
)),
|
||||
@ -184,7 +181,7 @@ class ACHelper {
|
||||
bool? removeComparators,
|
||||
}) {
|
||||
if (selectedFunction == 'temp_set' || selectedFunction == 'temp_current') {
|
||||
final initialValue = selectedFunctionData?.value ?? 200;
|
||||
final initialValue = selectedFunctionData?.value ?? 250;
|
||||
return _buildTemperatureSelector(
|
||||
context: context,
|
||||
initialValue: initialValue,
|
||||
@ -197,8 +194,7 @@ class ACHelper {
|
||||
);
|
||||
}
|
||||
|
||||
final selectedFn =
|
||||
acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final values = selectedFn.getOperationalValues();
|
||||
|
||||
return _buildOperationalValuesList(
|
||||
@ -294,8 +290,7 @@ class ACHelper {
|
||||
minHeight: 40.0,
|
||||
minWidth: 40.0,
|
||||
),
|
||||
isSelected:
|
||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
children: conditions.map((c) => Text(c)).toList(),
|
||||
);
|
||||
}
|
||||
@ -333,10 +328,10 @@ class ACHelper {
|
||||
String selectCode,
|
||||
) {
|
||||
return Slider(
|
||||
value: initialValue is int ? initialValue.toDouble() : 160.0,
|
||||
min: 160,
|
||||
value: initialValue is int ? initialValue.toDouble() : 200.0,
|
||||
min: 200,
|
||||
max: 300,
|
||||
divisions: 14,
|
||||
divisions: 10,
|
||||
label: '${((initialValue ?? 160) / 10).toInt()}°C',
|
||||
onChanged: (value) {
|
||||
context.read<FunctionBloc>().add(
|
||||
@ -389,13 +384,9 @@ class ACHelper {
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
trailing: Icon(
|
||||
isSelected
|
||||
? Icons.radio_button_checked
|
||||
: Icons.radio_button_unchecked,
|
||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||
size: 24,
|
||||
color: isSelected
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: ColorsManager.textGray,
|
||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
if (!isSelected) {
|
||||
@ -407,8 +398,7 @@ class ACHelper {
|
||||
operationName: operationName,
|
||||
value: value.value,
|
||||
condition: selectedFunctionData?.condition,
|
||||
valueDescription:
|
||||
selectedFunctionData?.valueDescription,
|
||||
valueDescription: selectedFunctionData?.valueDescription,
|
||||
),
|
||||
),
|
||||
);
|
@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class AutomationDialog extends StatefulWidget {
|
||||
@ -31,10 +31,8 @@ class _AutomationDialogState extends State<AutomationDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
List<DeviceFunctionData>? functions = context
|
||||
.read<RoutineBloc>()
|
||||
.state
|
||||
.selectedFunctions[widget.uniqueCustomId];
|
||||
List<DeviceFunctionData>? functions =
|
||||
context.read<RoutineBloc>().state.selectedFunctions[widget.uniqueCustomId];
|
||||
for (DeviceFunctionData data in functions ?? []) {
|
||||
if (data.entityId == widget.automationId) {
|
||||
selectedAutomationActionExecutor = data.value;
|
||||
@ -67,8 +65,7 @@ class _AutomationDialogState extends State<AutomationDialog> {
|
||||
}),
|
||||
),
|
||||
ListTile(
|
||||
leading:
|
||||
SvgPicture.asset(Assets.acPowerOff, width: 24, height: 24),
|
||||
leading: SvgPicture.asset(Assets.acPowerOff, width: 24, height: 24),
|
||||
title: const Text('Disable'),
|
||||
trailing: Radio<String?>(
|
||||
value: 'rule_disable',
|
@ -1,10 +1,10 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
|
||||
class DelayHelper {
|
||||
static Future<Map<String, dynamic>?> showDelayPickerDialog(
|
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/helper/duration_format_helper.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
@ -22,23 +22,21 @@ class OneGangSwitchHelper {
|
||||
String uniqueCustomId,
|
||||
bool removeComparetors,
|
||||
) async {
|
||||
List<BaseSwitchFunction> acFunctions =
|
||||
functions.whereType<BaseSwitchFunction>().toList();
|
||||
List<BaseSwitchFunction> acFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
||||
|
||||
return showDialog<Map<String, dynamic>?>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => FunctionBloc()
|
||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
child: AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||
builder: (context, state) {
|
||||
final selectedFunction = state.selectedFunction;
|
||||
final selectedOperationName = state.selectedOperationName;
|
||||
final selectedFunctionData = state.addedFunctions
|
||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
final selectedFunctionData =
|
||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
orElse: () => DeviceFunctionData(
|
||||
entityId: '',
|
||||
functionCode: selectedFunction ?? '',
|
||||
@ -85,12 +83,9 @@ class OneGangSwitchHelper {
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
context
|
||||
.read<FunctionBloc>()
|
||||
.add(SelectFunction(
|
||||
context.read<FunctionBloc>().add(SelectFunction(
|
||||
functionCode: function.code,
|
||||
operationName:
|
||||
function.operationName,
|
||||
operationName: function.operationName,
|
||||
));
|
||||
},
|
||||
);
|
||||
@ -180,8 +175,7 @@ class OneGangSwitchHelper {
|
||||
);
|
||||
}
|
||||
|
||||
final selectedFn =
|
||||
acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final values = selectedFn.getOperationalValues();
|
||||
|
||||
return _buildOperationalValuesList(
|
||||
@ -218,11 +212,11 @@ class OneGangSwitchHelper {
|
||||
selectedFunctionData,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||
selectedFunctionData, selectCode),
|
||||
_buildCountDownDisplay(
|
||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||
const SizedBox(height: 20),
|
||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||
selectedFunctionData, selectCode),
|
||||
_buildCountDownSlider(
|
||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -263,8 +257,7 @@ class OneGangSwitchHelper {
|
||||
minHeight: 40.0,
|
||||
minWidth: 40.0,
|
||||
),
|
||||
isSelected:
|
||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
children: conditions.map((c) => Text(c)).toList(),
|
||||
);
|
||||
}
|
||||
@ -312,8 +305,7 @@ class OneGangSwitchHelper {
|
||||
value: (initialValue ?? 0).toDouble(),
|
||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||
divisions: (((operationalValues.maxValue ?? 0) -
|
||||
(operationalValues.minValue ?? 0)) /
|
||||
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||
(operationalValues.stepValue ?? 1))
|
||||
.round(),
|
||||
onChanged: (value) {
|
||||
@ -365,13 +357,9 @@ class OneGangSwitchHelper {
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
trailing: Icon(
|
||||
isSelected
|
||||
? Icons.radio_button_checked
|
||||
: Icons.radio_button_unchecked,
|
||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||
size: 24,
|
||||
color: isSelected
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: ColorsManager.textGray,
|
||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
if (!isSelected) {
|
||||
@ -383,8 +371,7 @@ class OneGangSwitchHelper {
|
||||
operationName: operationName,
|
||||
value: value.value,
|
||||
condition: selectedFunctionData?.condition,
|
||||
valueDescription:
|
||||
selectedFunctionData?.valueDescription,
|
||||
valueDescription: selectedFunctionData?.valueDescription,
|
||||
),
|
||||
),
|
||||
);
|
@ -1,17 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_state.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/view/effective_period_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/delete_scene.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_state.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/icon_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/view/effective_period_view.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/delete_scene.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/helper/duration_format_helper.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
@ -22,23 +22,21 @@ class ThreeGangSwitchHelper {
|
||||
String uniqueCustomId,
|
||||
bool removeComparetors,
|
||||
) async {
|
||||
List<BaseSwitchFunction> switchFunctions =
|
||||
functions.whereType<BaseSwitchFunction>().toList();
|
||||
List<BaseSwitchFunction> switchFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
||||
|
||||
return showDialog<Map<String, dynamic>?>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => FunctionBloc()
|
||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
child: AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||
builder: (context, state) {
|
||||
final selectedFunction = state.selectedFunction;
|
||||
final selectedOperationName = state.selectedOperationName;
|
||||
final selectedFunctionData = state.addedFunctions
|
||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
final selectedFunctionData =
|
||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
orElse: () => DeviceFunctionData(
|
||||
entityId: '',
|
||||
functionCode: selectedFunction ?? '',
|
||||
@ -85,12 +83,9 @@ class ThreeGangSwitchHelper {
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
context
|
||||
.read<FunctionBloc>()
|
||||
.add(SelectFunction(
|
||||
context.read<FunctionBloc>().add(SelectFunction(
|
||||
functionCode: function.code,
|
||||
operationName:
|
||||
function.operationName,
|
||||
operationName: function.operationName,
|
||||
));
|
||||
},
|
||||
);
|
||||
@ -182,8 +177,7 @@ class ThreeGangSwitchHelper {
|
||||
);
|
||||
}
|
||||
|
||||
final selectedFn =
|
||||
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final values = selectedFn.getOperationalValues();
|
||||
|
||||
return _buildOperationalValuesList(
|
||||
@ -220,11 +214,11 @@ class ThreeGangSwitchHelper {
|
||||
selectedFunctionData,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||
selectedFunctionData, selectCode),
|
||||
_buildCountDownDisplay(
|
||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||
const SizedBox(height: 20),
|
||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||
selectedFunctionData, selectCode),
|
||||
_buildCountDownSlider(
|
||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -265,8 +259,7 @@ class ThreeGangSwitchHelper {
|
||||
minHeight: 40.0,
|
||||
minWidth: 40.0,
|
||||
),
|
||||
isSelected:
|
||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
children: conditions.map((c) => Text(c)).toList(),
|
||||
);
|
||||
}
|
||||
@ -314,8 +307,7 @@ class ThreeGangSwitchHelper {
|
||||
value: (initialValue ?? 0).toDouble(),
|
||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||
divisions: (((operationalValues.maxValue ?? 0) -
|
||||
(operationalValues.minValue ?? 0)) /
|
||||
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||
(operationalValues.stepValue ?? 1))
|
||||
.round(),
|
||||
onChanged: (value) {
|
||||
@ -367,13 +359,9 @@ class ThreeGangSwitchHelper {
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
trailing: Icon(
|
||||
isSelected
|
||||
? Icons.radio_button_checked
|
||||
: Icons.radio_button_unchecked,
|
||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||
size: 24,
|
||||
color: isSelected
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: ColorsManager.textGray,
|
||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
if (!isSelected) {
|
||||
@ -385,8 +373,7 @@ class ThreeGangSwitchHelper {
|
||||
operationName: operationName,
|
||||
value: value.value,
|
||||
condition: selectedFunctionData?.condition,
|
||||
valueDescription:
|
||||
selectedFunctionData?.valueDescription,
|
||||
valueDescription: selectedFunctionData?.valueDescription,
|
||||
),
|
||||
),
|
||||
);
|
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/helper/duration_format_helper.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
@ -22,23 +22,21 @@ class TwoGangSwitchHelper {
|
||||
String uniqueCustomId,
|
||||
bool removeComparetors,
|
||||
) async {
|
||||
List<BaseSwitchFunction> switchFunctions =
|
||||
functions.whereType<BaseSwitchFunction>().toList();
|
||||
List<BaseSwitchFunction> switchFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
||||
|
||||
return showDialog<Map<String, dynamic>?>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => FunctionBloc()
|
||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
child: AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||
builder: (context, state) {
|
||||
final selectedFunction = state.selectedFunction;
|
||||
final selectedOperationName = state.selectedOperationName;
|
||||
final selectedFunctionData = state.addedFunctions
|
||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
final selectedFunctionData =
|
||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
orElse: () => DeviceFunctionData(
|
||||
entityId: '',
|
||||
functionCode: selectedFunction ?? '',
|
||||
@ -85,12 +83,9 @@ class TwoGangSwitchHelper {
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
context
|
||||
.read<FunctionBloc>()
|
||||
.add(SelectFunction(
|
||||
context.read<FunctionBloc>().add(SelectFunction(
|
||||
functionCode: function.code,
|
||||
operationName:
|
||||
function.operationName,
|
||||
operationName: function.operationName,
|
||||
));
|
||||
},
|
||||
);
|
||||
@ -166,8 +161,7 @@ class TwoGangSwitchHelper {
|
||||
required String operationName,
|
||||
required bool removeComparetors,
|
||||
}) {
|
||||
if (selectedFunction == 'countdown_1' ||
|
||||
selectedFunction == 'countdown_2') {
|
||||
if (selectedFunction == 'countdown_1' || selectedFunction == 'countdown_2') {
|
||||
final initialValue = selectedFunctionData?.value ?? 200;
|
||||
return _buildTemperatureSelector(
|
||||
context: context,
|
||||
@ -181,8 +175,7 @@ class TwoGangSwitchHelper {
|
||||
);
|
||||
}
|
||||
|
||||
final selectedFn =
|
||||
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final values = selectedFn.getOperationalValues();
|
||||
|
||||
return _buildOperationalValuesList(
|
||||
@ -219,11 +212,11 @@ class TwoGangSwitchHelper {
|
||||
selectedFunctionData,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||
selectedFunctionData, selectCode),
|
||||
_buildCountDownDisplay(
|
||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||
const SizedBox(height: 20),
|
||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||
selectedFunctionData, selectCode),
|
||||
_buildCountDownSlider(
|
||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -264,8 +257,7 @@ class TwoGangSwitchHelper {
|
||||
minHeight: 40.0,
|
||||
minWidth: 40.0,
|
||||
),
|
||||
isSelected:
|
||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
children: conditions.map((c) => Text(c)).toList(),
|
||||
);
|
||||
}
|
||||
@ -313,8 +305,7 @@ class TwoGangSwitchHelper {
|
||||
value: (initialValue ?? 0).toDouble(),
|
||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||
divisions: (((operationalValues.maxValue ?? 0) -
|
||||
(operationalValues.minValue ?? 0)) /
|
||||
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||
(operationalValues.stepValue ?? 1))
|
||||
.round(),
|
||||
onChanged: (value) {
|
||||
@ -366,13 +357,9 @@ class TwoGangSwitchHelper {
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
trailing: Icon(
|
||||
isSelected
|
||||
? Icons.radio_button_checked
|
||||
: Icons.radio_button_unchecked,
|
||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||
size: 24,
|
||||
color: isSelected
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: ColorsManager.textGray,
|
||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
if (!isSelected) {
|
||||
@ -384,8 +371,7 @@ class TwoGangSwitchHelper {
|
||||
operationName: operationName,
|
||||
value: value.value,
|
||||
condition: selectedFunctionData?.condition,
|
||||
valueDescription:
|
||||
selectedFunctionData?.valueDescription,
|
||||
valueDescription: selectedFunctionData?.valueDescription,
|
||||
),
|
||||
),
|
||||
);
|
@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/helper/save_routine_helper.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/discard_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/setting_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/helper/save_routine_helper.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/discard_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/setting_dialog.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
@ -1,7 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class ScenesAndAutomations extends StatefulWidget {
|
||||
@ -18,8 +19,9 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>()
|
||||
..add(const LoadScenes(spaceId, communityId))
|
||||
..add(const LoadAutomation(spaceId));
|
||||
..add(LoadScenes(context.read<SpaceTreeBloc>().selectedSpaceId,
|
||||
context.read<SpaceTreeBloc>().selectedCommunityId))
|
||||
..add(LoadAutomation(context.read<SpaceTreeBloc>().selectedSpaceId));
|
||||
}
|
||||
|
||||
@override
|
||||
@ -34,9 +36,7 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
|
||||
children: scenes.asMap().entries.map((entry) {
|
||||
final scene = entry.value;
|
||||
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
||||
return scene.name
|
||||
.toLowerCase()
|
||||
.contains(state.searchText!.toLowerCase())
|
||||
return scene.name.toLowerCase().contains(state.searchText!.toLowerCase())
|
||||
? DraggableCard(
|
||||
imagePath: scene.icon ?? Assets.loginLogo,
|
||||
title: scene.name,
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routines_title_widget.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routines_title_widget.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/automation_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/delay_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/helper/dialog_helper/device_dialog_helper.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/automation_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/delay_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/helper/dialog_helper/device_dialog_helper.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
291
lib/pages/space_tree/bloc/space_tree_bloc.dart
Normal file
291
lib/pages/space_tree/bloc/space_tree_bloc.dart
Normal file
@ -0,0 +1,291 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||
|
||||
class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
String selectedCommunityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||
String selectedSpaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
|
||||
SpaceTreeBloc() : super(const SpaceTreeState()) {
|
||||
on<InitialEvent>(_fetchSpaces);
|
||||
on<OnCommunityExpanded>(_onCommunityExpanded);
|
||||
on<OnSpaceExpanded>(_onSpaceExpanded);
|
||||
on<OnCommunitySelected>(_onCommunitySelected);
|
||||
on<OnSpaceSelected>(_onSpaceSelected);
|
||||
on<SearchQueryEvent>(_onSearch);
|
||||
}
|
||||
|
||||
_fetchSpaces(InitialEvent event, Emitter<SpaceTreeState> emit) async {
|
||||
emit(SpaceTreeLoadingState());
|
||||
try {
|
||||
List<CommunityModel> communities = await CommunitySpaceManagementApi().fetchCommunities();
|
||||
|
||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
||||
communities.map((community) async {
|
||||
List<SpaceModel> spaces =
|
||||
await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid);
|
||||
|
||||
return CommunityModel(
|
||||
uuid: community.uuid,
|
||||
createdAt: community.createdAt,
|
||||
updatedAt: community.updatedAt,
|
||||
name: community.name,
|
||||
description: community.description,
|
||||
spaces: spaces,
|
||||
region: community.region,
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
|
||||
emit(state.copyWith(
|
||||
communitiesList: updatedCommunities, expandedCommunity: [], expandedSpaces: []));
|
||||
} catch (e) {
|
||||
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
_onCommunityExpanded(OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
List<String> updatedExpandedCommunityList = List.from(state.expandedCommunities);
|
||||
|
||||
if (updatedExpandedCommunityList.contains(event.communityId)) {
|
||||
updatedExpandedCommunityList.remove(event.communityId);
|
||||
} else {
|
||||
updatedExpandedCommunityList.add(event.communityId);
|
||||
}
|
||||
|
||||
emit(state.copyWith(
|
||||
expandedCommunity: updatedExpandedCommunityList,
|
||||
));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
_onSpaceExpanded(OnSpaceExpanded event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
List<String> updatedExpandedSpacesList = List.from(state.expandedSpaces);
|
||||
|
||||
if (updatedExpandedSpacesList.contains(event.spaceId)) {
|
||||
updatedExpandedSpacesList.remove(event.spaceId);
|
||||
} else {
|
||||
updatedExpandedSpacesList.add(event.spaceId);
|
||||
}
|
||||
|
||||
emit(state.copyWith(expandedSpaces: updatedExpandedSpacesList));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
_onCommunitySelected(OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
List<String> updatedSelectedCommunities =
|
||||
List.from(state.selectedCommunities.toSet().toList());
|
||||
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||
|
||||
List<String> childrenIds = _getAllChildIds(event.children);
|
||||
|
||||
if (!updatedSelectedCommunities.contains(event.communityId)) {
|
||||
// Select the community and all its children
|
||||
updatedSelectedCommunities.add(event.communityId);
|
||||
updatedSelectedSpaces.addAll(childrenIds);
|
||||
} else {
|
||||
// Unselect the community and all its children
|
||||
updatedSelectedCommunities.remove(event.communityId);
|
||||
updatedSelectedSpaces.removeWhere(childrenIds.contains);
|
||||
updatedSoldChecks.removeWhere(childrenIds.contains);
|
||||
}
|
||||
|
||||
communityAndSpaces[event.communityId] = updatedSelectedSpaces;
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedCommunities: updatedSelectedCommunities,
|
||||
selectedSpaces: updatedSelectedSpaces,
|
||||
soldCheck: updatedSoldChecks,
|
||||
selectedCommunityAndSpaces: communityAndSpaces));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
_onSpaceSelected(OnSpaceSelected event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
List<String> updatedSelectedCommunities =
|
||||
List.from(state.selectedCommunities.toSet().toList());
|
||||
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||
|
||||
List<String> childrenIds = _getAllChildIds(event.children);
|
||||
bool isChildSelected = false;
|
||||
|
||||
for (String id in childrenIds) {
|
||||
if (updatedSelectedSpaces.contains(id)) {
|
||||
isChildSelected = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!updatedSelectedSpaces.contains(event.spaceId) &&
|
||||
!updatedSoldChecks.contains(event.spaceId)) {
|
||||
// First click: Select the space and all its children
|
||||
updatedSelectedSpaces.add(event.spaceId);
|
||||
updatedSelectedCommunities.add(event.communityId);
|
||||
if (childrenIds.isNotEmpty) {
|
||||
updatedSelectedSpaces.addAll(childrenIds);
|
||||
}
|
||||
|
||||
List<String> spaces = _getThePathToChild(event.communityId, event.spaceId);
|
||||
for (String space in spaces) {
|
||||
if (!updatedSelectedSpaces.contains(space) && !updatedSoldChecks.contains(space)) {
|
||||
updatedSoldChecks.add(space);
|
||||
}
|
||||
}
|
||||
} else if (!updatedSoldChecks.contains(event.spaceId) &&
|
||||
childrenIds.isNotEmpty &&
|
||||
isChildSelected) {
|
||||
// Second click: Unselect space but keep children
|
||||
updatedSelectedSpaces.remove(event.spaceId);
|
||||
updatedSoldChecks.add(event.spaceId);
|
||||
} else {
|
||||
// Third click: Unselect space and all its children
|
||||
updatedSelectedSpaces.remove(event.spaceId);
|
||||
if (childrenIds.isNotEmpty) {
|
||||
updatedSelectedSpaces.removeWhere(childrenIds.contains);
|
||||
updatedSoldChecks.removeWhere(childrenIds.contains);
|
||||
}
|
||||
updatedSoldChecks.remove(event.spaceId);
|
||||
|
||||
List<String> parents = _getThePathToChild(event.communityId, event.spaceId);
|
||||
if (!_parentSelected(parents, updatedSelectedSpaces)) {
|
||||
updatedSoldChecks.removeWhere(parents.contains);
|
||||
}
|
||||
if (!_anySpacesSelectedInCommunity(
|
||||
event.communityId, updatedSelectedSpaces, updatedSoldChecks)) {
|
||||
updatedSelectedCommunities.remove(event.communityId);
|
||||
}
|
||||
}
|
||||
|
||||
communityAndSpaces[event.communityId] = updatedSelectedSpaces;
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedCommunities: updatedSelectedCommunities,
|
||||
selectedSpaces: updatedSelectedSpaces,
|
||||
soldCheck: updatedSoldChecks,
|
||||
selectedCommunityAndSpaces: communityAndSpaces));
|
||||
emit(state.copyWith(selectedSpaces: updatedSelectedSpaces));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
_parentSelected(List<String> parents, List<String> selectedSpaces) {
|
||||
for (String space in parents) {
|
||||
if (selectedSpaces.contains(space)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_onSearch(SearchQueryEvent event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
List<CommunityModel> communities = List.from(state.communityList);
|
||||
List<CommunityModel> filteredCommunity = [];
|
||||
|
||||
// Filter communities and expand only those that match the query
|
||||
filteredCommunity = communities.where((community) {
|
||||
final containsQueryInCommunity =
|
||||
community.name.toLowerCase().contains(event.searchQuery.toLowerCase());
|
||||
final containsQueryInSpaces =
|
||||
community.spaces.any((space) => _containsQuery(space, event.searchQuery.toLowerCase()));
|
||||
|
||||
return containsQueryInCommunity || containsQueryInSpaces;
|
||||
}).toList();
|
||||
|
||||
emit(state.copyWith(
|
||||
filteredCommunity: filteredCommunity, isSearching: event.searchQuery.isNotEmpty));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to determine if any space or its children match the search query
|
||||
bool _containsQuery(SpaceModel space, String query) {
|
||||
final matchesSpace = space.name.toLowerCase().contains(query);
|
||||
final matchesChildren =
|
||||
space.children.any((child) => _containsQuery(child, query)); // Recursive check for children
|
||||
|
||||
return matchesSpace || matchesChildren;
|
||||
}
|
||||
|
||||
List<String> _getAllChildIds(List<SpaceModel> spaces) {
|
||||
List<String> ids = [];
|
||||
for (var child in spaces) {
|
||||
ids.add(child.uuid!);
|
||||
ids.addAll(_getAllChildIds(child.children));
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
bool _anySpacesSelectedInCommunity(
|
||||
String communityId, List<String> selectedSpaces, List<String> partialCheckedList) {
|
||||
bool result = false;
|
||||
for (var community in state.communityList) {
|
||||
if (community.uuid == communityId) {
|
||||
List<String> ids = _getAllChildIds(community.spaces);
|
||||
for (var id in ids) {
|
||||
result = selectedSpaces.contains(id) || partialCheckedList.contains(id);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
List<String> _getThePathToChild(String communityId, String selectedSpaceId) {
|
||||
List<String> ids = [];
|
||||
for (var community in state.communityList) {
|
||||
if (community.uuid == communityId) {
|
||||
for (var space in community.spaces) {
|
||||
List<String> list = [];
|
||||
list.add(space.uuid!);
|
||||
ids = _getAllParentsIds(space, selectedSpaceId, List.from(list));
|
||||
if (ids.isNotEmpty) {
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
List<String> _getAllParentsIds(SpaceModel child, String spaceId, List<String> listIds) {
|
||||
List<String> ids = listIds;
|
||||
|
||||
ids.add(child.uuid ?? '');
|
||||
|
||||
if (child.uuid == spaceId) {
|
||||
return ids;
|
||||
}
|
||||
|
||||
if (child.children.isNotEmpty) {
|
||||
for (var space in child.children) {
|
||||
var result = _getAllParentsIds(space, spaceId, List.from(ids));
|
||||
if (result.isNotEmpty) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ids.removeLast();
|
||||
return [];
|
||||
}
|
||||
}
|
69
lib/pages/space_tree/bloc/space_tree_event.dart
Normal file
69
lib/pages/space_tree/bloc/space_tree_event.dart
Normal file
@ -0,0 +1,69 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
|
||||
class SpaceTreeEvent extends Equatable {
|
||||
const SpaceTreeEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class InitialEvent extends SpaceTreeEvent {}
|
||||
|
||||
class SearchForSpace extends SpaceTreeEvent {
|
||||
final String searchQuery;
|
||||
|
||||
const SearchForSpace(this.searchQuery);
|
||||
|
||||
@override
|
||||
List<Object> get props => [searchQuery];
|
||||
}
|
||||
|
||||
class OnCommunityExpanded extends SpaceTreeEvent {
|
||||
final String communityId;
|
||||
|
||||
const OnCommunityExpanded(this.communityId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [communityId];
|
||||
}
|
||||
|
||||
class OnCommunitySelected extends SpaceTreeEvent {
|
||||
final String communityId;
|
||||
final List<SpaceModel> children;
|
||||
|
||||
const OnCommunitySelected(this.communityId, this.children);
|
||||
|
||||
@override
|
||||
List<Object> get props => [communityId, children];
|
||||
}
|
||||
|
||||
class OnSpaceExpanded extends SpaceTreeEvent {
|
||||
final String communityId;
|
||||
final String spaceId;
|
||||
|
||||
const OnSpaceExpanded(this.communityId, this.spaceId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [communityId, spaceId];
|
||||
}
|
||||
|
||||
class OnSpaceSelected extends SpaceTreeEvent {
|
||||
final String communityId;
|
||||
final String spaceId;
|
||||
final List<SpaceModel> children;
|
||||
|
||||
const OnSpaceSelected(this.communityId, this.spaceId, this.children);
|
||||
|
||||
@override
|
||||
List<Object> get props => [communityId, spaceId, children];
|
||||
}
|
||||
|
||||
class SearchQueryEvent extends SpaceTreeEvent {
|
||||
final String searchQuery;
|
||||
|
||||
const SearchQueryEvent(this.searchQuery);
|
||||
|
||||
@override
|
||||
List<Object> get props => [searchQuery];
|
||||
}
|
70
lib/pages/space_tree/bloc/space_tree_state.dart
Normal file
70
lib/pages/space_tree/bloc/space_tree_state.dart
Normal file
@ -0,0 +1,70 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
|
||||
class SpaceTreeState extends Equatable {
|
||||
final Map<String, List<String>> selectedCommunityAndSpaces;
|
||||
final List<CommunityModel> communityList;
|
||||
final List<CommunityModel> filteredCommunity;
|
||||
final List<String> expandedCommunities;
|
||||
final List<String> expandedSpaces;
|
||||
final List<String> selectedCommunities;
|
||||
final List<String> selectedSpaces;
|
||||
final List<String> soldCheck;
|
||||
final bool isSearching;
|
||||
|
||||
const SpaceTreeState(
|
||||
{this.communityList = const [],
|
||||
this.filteredCommunity = const [],
|
||||
this.expandedCommunities = const [],
|
||||
this.expandedSpaces = const [],
|
||||
this.selectedCommunities = const [],
|
||||
this.selectedSpaces = const [],
|
||||
this.soldCheck = const [],
|
||||
this.isSearching = false,
|
||||
this.selectedCommunityAndSpaces = const {}});
|
||||
|
||||
SpaceTreeState copyWith(
|
||||
{List<CommunityModel>? communitiesList,
|
||||
List<CommunityModel>? filteredCommunity,
|
||||
List<String>? expandedSpaces,
|
||||
List<String>? expandedCommunity,
|
||||
List<String>? selectedCommunities,
|
||||
List<String>? selectedSpaces,
|
||||
List<String>? soldCheck,
|
||||
bool? isSearching,
|
||||
Map<String, List<String>>? selectedCommunityAndSpaces}) {
|
||||
return SpaceTreeState(
|
||||
communityList: communitiesList ?? this.communityList,
|
||||
filteredCommunity: filteredCommunity ?? this.filteredCommunity,
|
||||
expandedSpaces: expandedSpaces ?? this.expandedSpaces,
|
||||
expandedCommunities: expandedCommunity ?? this.expandedCommunities,
|
||||
selectedCommunities: selectedCommunities ?? this.selectedCommunities,
|
||||
selectedSpaces: selectedSpaces ?? this.selectedSpaces,
|
||||
soldCheck: soldCheck ?? this.soldCheck,
|
||||
isSearching: isSearching ?? this.isSearching,
|
||||
selectedCommunityAndSpaces: selectedCommunityAndSpaces ?? this.selectedCommunityAndSpaces);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
communityList,
|
||||
filteredCommunity,
|
||||
expandedSpaces,
|
||||
expandedCommunities,
|
||||
selectedCommunities,
|
||||
selectedSpaces,
|
||||
soldCheck,
|
||||
isSearching,
|
||||
selectedCommunityAndSpaces
|
||||
];
|
||||
}
|
||||
|
||||
class SpaceTreeLoadingState extends SpaceTreeState {}
|
||||
|
||||
class SpaceTreeErrorState extends SpaceTreeState {
|
||||
final String message;
|
||||
const SpaceTreeErrorState(this.message);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [message];
|
||||
}
|
99
lib/pages/space_tree/view/custom_expansion.dart
Normal file
99
lib/pages/space_tree/view/custom_expansion.dart
Normal file
@ -0,0 +1,99 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class CustomExpansionTileSpaceTree extends StatelessWidget {
|
||||
final String? spaceId;
|
||||
final String title;
|
||||
final List<Widget>? children;
|
||||
final bool isSelected;
|
||||
final bool isSoldCheck;
|
||||
final bool isExpanded;
|
||||
final Function? onExpansionChanged;
|
||||
final Function? onItemSelected;
|
||||
|
||||
const CustomExpansionTileSpaceTree(
|
||||
{super.key,
|
||||
this.spaceId,
|
||||
required this.title,
|
||||
this.children,
|
||||
this.isExpanded = false,
|
||||
this.onExpansionChanged,
|
||||
this.onItemSelected,
|
||||
required this.isSelected,
|
||||
this.isSoldCheck = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: isSoldCheck ? null : isSelected,
|
||||
onChanged: (bool? value) {
|
||||
if (onItemSelected != null) {
|
||||
onItemSelected!();
|
||||
}
|
||||
},
|
||||
tristate: true,
|
||||
side: WidgetStateBorderSide.resolveWith((states) {
|
||||
return const BorderSide(color: ColorsManager.grayBorder);
|
||||
}),
|
||||
fillColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return ColorsManager.blue1;
|
||||
} else {
|
||||
return ColorsManager.checkBoxFillColor;
|
||||
}
|
||||
}),
|
||||
checkColor: ColorsManager.whiteColors,
|
||||
),
|
||||
if (children != null && children!.isNotEmpty)
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if (onExpansionChanged != null) {
|
||||
onExpansionChanged!();
|
||||
}
|
||||
},
|
||||
child: Icon(
|
||||
isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right,
|
||||
color: ColorsManager.lightGrayColor,
|
||||
size: 16.0,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (onItemSelected != null) {
|
||||
onItemSelected!();
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
_capitalizeFirstLetter(title),
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: isSelected
|
||||
? ColorsManager.blackColor // Change color to black when selected
|
||||
: ColorsManager.lightGrayColor, // Gray when not selected
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isExpanded && children != null && children!.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 48.0),
|
||||
child: Column(
|
||||
children: children ?? [],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String _capitalizeFirstLetter(String text) {
|
||||
if (text.isEmpty) return text;
|
||||
return text[0].toUpperCase() + text.substring(1);
|
||||
}
|
||||
}
|
220
lib/pages/space_tree/view/space_tree_view.dart
Normal file
220
lib/pages/space_tree/view/space_tree_view.dart
Normal file
@ -0,0 +1,220 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/common/widgets/search_bar.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/custom_expansion.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class SpaceTreeView extends StatefulWidget {
|
||||
final Function onSelect;
|
||||
const SpaceTreeView({required this.onSelect, super.key});
|
||||
|
||||
@override
|
||||
State<SpaceTreeView> createState() => _SpaceTreeViewState();
|
||||
}
|
||||
|
||||
class _SpaceTreeViewState extends State<SpaceTreeView> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<SpaceTreeBloc, SpaceTreeState>(builder: (context, state) {
|
||||
List<CommunityModel> list = state.isSearching ? state.filteredCommunity : state.communityList;
|
||||
return Container(
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
decoration: subSectionContainerDecoration,
|
||||
child: state is SpaceTreeLoadingState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
children: [
|
||||
CustomSearchBar(
|
||||
onSearchChanged: (query) {
|
||||
context.read<SpaceTreeBloc>().add(SearchQueryEvent(query));
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.sizeOf(context).width * 0.5,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: list.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
'No results found',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Scrollbar(
|
||||
scrollbarOrientation: ScrollbarOrientation.left,
|
||||
thumbVisibility: true,
|
||||
controller: _scrollController,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: ListView(
|
||||
controller: _scrollController,
|
||||
shrinkWrap: true,
|
||||
children: list
|
||||
.map(
|
||||
(community) => CustomExpansionTileSpaceTree(
|
||||
title: community.name,
|
||||
isSelected: state.selectedCommunities
|
||||
.contains(community.uuid),
|
||||
isSoldCheck: state.selectedCommunities
|
||||
.contains(community.uuid),
|
||||
onExpansionChanged: () {
|
||||
context
|
||||
.read<SpaceTreeBloc>()
|
||||
.add(OnCommunityExpanded(community.uuid));
|
||||
},
|
||||
isExpanded: state.expandedCommunities
|
||||
.contains(community.uuid),
|
||||
onItemSelected: () {
|
||||
context.read<SpaceTreeBloc>().add(
|
||||
OnCommunitySelected(
|
||||
community.uuid, community.spaces));
|
||||
widget.onSelect();
|
||||
},
|
||||
children: community.spaces.map((space) {
|
||||
return CustomExpansionTileSpaceTree(
|
||||
title: space.name,
|
||||
isExpanded:
|
||||
state.expandedSpaces.contains(space.uuid),
|
||||
onItemSelected: () {
|
||||
context.read<SpaceTreeBloc>().add(
|
||||
OnSpaceSelected(community.uuid,
|
||||
space.uuid ?? '', space.children));
|
||||
widget.onSelect();
|
||||
},
|
||||
onExpansionChanged: () {
|
||||
context.read<SpaceTreeBloc>().add(
|
||||
OnSpaceExpanded(
|
||||
community.uuid, space.uuid ?? ''));
|
||||
},
|
||||
isSelected:
|
||||
state.selectedSpaces.contains(space.uuid) ||
|
||||
state.soldCheck.contains(space.uuid),
|
||||
isSoldCheck: state.soldCheck.contains(space.uuid),
|
||||
children: _buildNestedSpaces(
|
||||
context, state, space, community.uuid),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Expanded(
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: list.isEmpty
|
||||
// ? Center(
|
||||
// child: Text(
|
||||
// 'No results found',
|
||||
// style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
// color: ColorsManager.lightGrayColor, // Gray when not selected
|
||||
// fontWeight: FontWeight.w400,
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// : ListView(
|
||||
// shrinkWrap: true,
|
||||
// children: list
|
||||
// .map(
|
||||
// (community) => CustomExpansionTileSpaceTree(
|
||||
// title: community.name,
|
||||
// isSelected:
|
||||
// state.selectedCommunities.contains(community.uuid),
|
||||
// isSoldCheck:
|
||||
// state.selectedCommunities.contains(community.uuid),
|
||||
// onExpansionChanged: () {
|
||||
// context
|
||||
// .read<SpaceTreeBloc>()
|
||||
// .add(OnCommunityExpanded(community.uuid));
|
||||
// },
|
||||
// isExpanded:
|
||||
// state.expandedCommunities.contains(community.uuid),
|
||||
// onItemSelected: () {
|
||||
// context.read<SpaceTreeBloc>().add(
|
||||
// OnCommunitySelected(community.uuid, community.spaces));
|
||||
|
||||
// onSelect();
|
||||
// },
|
||||
// children: community.spaces.map((space) {
|
||||
// return CustomExpansionTileSpaceTree(
|
||||
// title: space.name,
|
||||
// isExpanded: state.expandedSpaces.contains(space.uuid),
|
||||
// onItemSelected: () {
|
||||
// context.read<SpaceTreeBloc>().add(OnSpaceSelected(
|
||||
// community.uuid, space.uuid ?? '', space.children));
|
||||
// onSelect();
|
||||
// },
|
||||
// onExpansionChanged: () {
|
||||
// context.read<SpaceTreeBloc>().add(
|
||||
// OnSpaceExpanded(community.uuid, space.uuid ?? ''));
|
||||
// },
|
||||
// isSelected: state.selectedSpaces.contains(space.uuid) ||
|
||||
// state.soldCheck.contains(space.uuid),
|
||||
// isSoldCheck: state.soldCheck.contains(space.uuid),
|
||||
// children: _buildNestedSpaces(
|
||||
// context, state, space, community.uuid),
|
||||
// );
|
||||
// }).toList(),
|
||||
// ),
|
||||
// )
|
||||
// .toList(),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
List<Widget> _buildNestedSpaces(
|
||||
BuildContext context, SpaceTreeState state, SpaceModel space, String communityId) {
|
||||
return space.children.map((child) {
|
||||
return CustomExpansionTileSpaceTree(
|
||||
isSelected:
|
||||
state.selectedSpaces.contains(child.uuid) || state.soldCheck.contains(child.uuid),
|
||||
isSoldCheck: state.soldCheck.contains(child.uuid),
|
||||
title: child.name,
|
||||
isExpanded: state.expandedSpaces.contains(child.uuid),
|
||||
onItemSelected: () {
|
||||
context
|
||||
.read<SpaceTreeBloc>()
|
||||
.add(OnSpaceSelected(communityId, child.uuid ?? '', child.children));
|
||||
widget.onSelect();
|
||||
},
|
||||
onExpansionChanged: () {
|
||||
context.read<SpaceTreeBloc>().add(OnSpaceExpanded(communityId, child.uuid ?? ''));
|
||||
},
|
||||
children: _buildNestedSpaces(context, state, child, communityId),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
}
|
@ -1,38 +1,74 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/bloc/add_device_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/bloc/add_device_type_model_event.dart';
|
||||
|
||||
class AddDeviceTypeBloc
|
||||
extends Bloc<AddDeviceTypeEvent, List<SelectedProduct>> {
|
||||
AddDeviceTypeBloc(List<SelectedProduct> initialProducts)
|
||||
: super(initialProducts) {
|
||||
class AddDeviceTypeBloc extends Bloc<AddDeviceTypeEvent, AddDeviceState> {
|
||||
AddDeviceTypeBloc() : super(AddDeviceInitial()) {
|
||||
on<InitializeDevice>(_onInitializeTagModels);
|
||||
on<UpdateProductCountEvent>(_onUpdateProductCount);
|
||||
}
|
||||
|
||||
void _onInitializeTagModels(
|
||||
InitializeDevice event, Emitter<AddDeviceState> emit) {
|
||||
emit(AddDeviceLoaded(
|
||||
selectedProducts: event.addedProducts,
|
||||
initialTag: event.initialTags,
|
||||
));
|
||||
}
|
||||
|
||||
void _onUpdateProductCount(
|
||||
UpdateProductCountEvent event, Emitter<List<SelectedProduct>> emit) {
|
||||
final existingProduct = state.firstWhere(
|
||||
UpdateProductCountEvent event, Emitter<AddDeviceState> emit) {
|
||||
final currentState = state;
|
||||
|
||||
if (currentState is AddDeviceLoaded) {
|
||||
final existingProduct = currentState.selectedProducts.firstWhere(
|
||||
(p) => p.productId == event.productId,
|
||||
orElse: () => SelectedProduct(productId: event.productId, count: 0,productName: event.productName,product: event.product ),
|
||||
orElse: () => SelectedProduct(
|
||||
productId: event.productId,
|
||||
count: 0,
|
||||
productName: event.productName,
|
||||
product: event.product,
|
||||
),
|
||||
);
|
||||
|
||||
List<SelectedProduct> updatedProducts;
|
||||
|
||||
if (event.count > 0) {
|
||||
if (!state.contains(existingProduct)) {
|
||||
emit([
|
||||
...state,
|
||||
SelectedProduct(productId: event.productId, count: event.count, productName: event.productName, product: event.product)
|
||||
]);
|
||||
if (!currentState.selectedProducts.contains(existingProduct)) {
|
||||
updatedProducts = [
|
||||
...currentState.selectedProducts,
|
||||
SelectedProduct(
|
||||
productId: event.productId,
|
||||
count: event.count,
|
||||
productName: event.productName,
|
||||
product: event.product,
|
||||
),
|
||||
];
|
||||
} else {
|
||||
final updatedList = state.map((p) {
|
||||
updatedProducts = currentState.selectedProducts.map((p) {
|
||||
if (p.productId == event.productId) {
|
||||
return SelectedProduct(productId: p.productId, count: event.count, productName: p.productName,product: p.product);
|
||||
return SelectedProduct(
|
||||
productId: p.productId,
|
||||
count: event.count,
|
||||
productName: p.productName,
|
||||
product: p.product,
|
||||
);
|
||||
}
|
||||
return p;
|
||||
}).toList();
|
||||
emit(updatedList);
|
||||
}
|
||||
} else {
|
||||
emit(state.where((p) => p.productId != event.productId).toList());
|
||||
// Remove the product if the count is 0
|
||||
updatedProducts = currentState.selectedProducts
|
||||
.where((p) => p.productId != event.productId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Emit the updated state
|
||||
emit(AddDeviceLoaded(
|
||||
selectedProducts: updatedProducts,
|
||||
initialTag: currentState.initialTag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||
|
||||
abstract class AddDeviceState extends Equatable {
|
||||
const AddDeviceState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class AddDeviceInitial extends AddDeviceState {}
|
||||
|
||||
class AddDeviceLoading extends AddDeviceState {}
|
||||
|
||||
class AddDeviceLoaded extends AddDeviceState {
|
||||
final List<SelectedProduct> selectedProducts;
|
||||
final List<Tag> initialTag;
|
||||
|
||||
const AddDeviceLoaded({
|
||||
required this.selectedProducts,
|
||||
required this.initialTag,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [selectedProducts, initialTag];
|
||||
}
|
||||
|
||||
class AddDeviceError extends AddDeviceState {
|
||||
final String errorMessage;
|
||||
|
||||
const AddDeviceError(this.errorMessage);
|
||||
|
||||
@override
|
||||
List<Object> get props => [errorMessage];
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||
|
||||
abstract class AddDeviceTypeEvent extends Equatable {
|
||||
const AddDeviceTypeEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
@ -12,8 +16,26 @@ class UpdateProductCountEvent extends AddDeviceTypeEvent {
|
||||
final String productName;
|
||||
final ProductModel product;
|
||||
|
||||
UpdateProductCountEvent({required this.productId, required this.count, required this.productName, required this.product});
|
||||
UpdateProductCountEvent(
|
||||
{required this.productId,
|
||||
required this.count,
|
||||
required this.productName,
|
||||
required this.product});
|
||||
|
||||
@override
|
||||
List<Object> get props => [productId, count];
|
||||
}
|
||||
|
||||
|
||||
class InitializeDevice extends AddDeviceTypeEvent {
|
||||
final List<Tag> initialTags;
|
||||
final List<SelectedProduct> addedProducts;
|
||||
|
||||
const InitializeDevice({
|
||||
this.initialTags = const [],
|
||||
required this.addedProducts,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [initialTags, addedProducts];
|
||||
}
|
||||
|
@ -1,17 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/bloc/add_device_model_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/bloc/add_device_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/bloc/add_device_type_model_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/widgets/scrollable_grid_view_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/action_button_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
|
||||
class AddDeviceTypeWidget extends StatelessWidget {
|
||||
final List<ProductModel>? products;
|
||||
final ValueChanged<List<SelectedProduct>>? onProductsSelected;
|
||||
@ -20,11 +22,12 @@ class AddDeviceTypeWidget extends StatelessWidget {
|
||||
final List<Tag>? spaceTags;
|
||||
final List<String>? allTags;
|
||||
final String spaceName;
|
||||
final bool isCreate;
|
||||
final Function(List<Tag>, List<SubspaceModel>?)? onSave;
|
||||
|
||||
|
||||
const AddDeviceTypeWidget(
|
||||
{super.key,
|
||||
required this.isCreate,
|
||||
this.products,
|
||||
this.initialSelectedProducts,
|
||||
this.onProductsSelected,
|
||||
@ -44,12 +47,22 @@ class AddDeviceTypeWidget extends StatelessWidget {
|
||||
: 3;
|
||||
|
||||
return BlocProvider(
|
||||
create: (_) => AddDeviceTypeBloc(initialSelectedProducts ?? []),
|
||||
create: (_) => AddDeviceTypeBloc()
|
||||
..add(InitializeDevice(
|
||||
initialTags: spaceTags ?? [],
|
||||
addedProducts: initialSelectedProducts ?? [],
|
||||
)),
|
||||
child: Builder(
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Add Devices'),
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
content: SingleChildScrollView(
|
||||
content: BlocBuilder<AddDeviceTypeBloc, AddDeviceState>(
|
||||
builder: (context, state) {
|
||||
if (state is AddDeviceLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (state is AddDeviceLoaded) {
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
width: size.width * 0.9,
|
||||
height: size.height * 0.65,
|
||||
@ -59,15 +72,22 @@ class AddDeviceTypeWidget extends StatelessWidget {
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: ScrollableGridViewWidget(
|
||||
products: products, crossAxisCount: crossAxisCount),
|
||||
initialProductCounts: state.selectedProducts,
|
||||
products: products,
|
||||
isCreate: isCreate,
|
||||
crossAxisCount: crossAxisCount),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox();
|
||||
}),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@ -78,20 +98,27 @@ class AddDeviceTypeWidget extends StatelessWidget {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ActionButton(
|
||||
label: 'Continue',
|
||||
SizedBox(
|
||||
width: 140,
|
||||
child: BlocBuilder<AddDeviceTypeBloc, AddDeviceState>(
|
||||
builder: (context, state) {
|
||||
final isDisabled = state is AddDeviceLoaded &&
|
||||
state.selectedProducts.isEmpty;
|
||||
return DefaultButton(
|
||||
borderRadius: 10,
|
||||
backgroundColor: ColorsManager.secondaryColor,
|
||||
foregroundColor: ColorsManager.whiteColors,
|
||||
foregroundColor: isDisabled
|
||||
? ColorsManager.whiteColorsWithOpacity
|
||||
: ColorsManager.whiteColors,
|
||||
onPressed: () async {
|
||||
final currentState =
|
||||
context.read<AddDeviceTypeBloc>().state;
|
||||
Navigator.of(context).pop();
|
||||
|
||||
if (currentState.isNotEmpty) {
|
||||
final initialTags = generateInitialTags(
|
||||
if (state is AddDeviceLoaded &&
|
||||
state.selectedProducts.isNotEmpty) {
|
||||
final initialTags =
|
||||
TagHelper.generateInitialForTags(
|
||||
spaceTags: spaceTags,
|
||||
subspaces: subspaces,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
|
||||
final dialogTitle = initialTags.isNotEmpty
|
||||
? 'Edit Device'
|
||||
@ -102,48 +129,23 @@ class AddDeviceTypeWidget extends StatelessWidget {
|
||||
builder: (context) => AssignTagDialog(
|
||||
products: products,
|
||||
subspaces: subspaces,
|
||||
addedProducts: currentState,
|
||||
addedProducts: state.selectedProducts,
|
||||
allTags: allTags,
|
||||
spaceName: spaceName,
|
||||
initialTags: initialTags,
|
||||
title: dialogTitle,
|
||||
onSave: (tags,subspaces){
|
||||
onSave!(tags,subspaces);
|
||||
},
|
||||
),
|
||||
onSave: onSave),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
child: const Text('Next'),
|
||||
);
|
||||
},
|
||||
)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
List<Tag> generateInitialTags({
|
||||
List<Tag>? spaceTags,
|
||||
List<SubspaceModel>? subspaces,
|
||||
}) {
|
||||
final List<Tag> initialTags = [];
|
||||
|
||||
if (spaceTags != null) {
|
||||
initialTags.addAll(spaceTags);
|
||||
}
|
||||
|
||||
if (subspaces != null) {
|
||||
for (var subspace in subspaces) {
|
||||
if (subspace.tags != null) {
|
||||
initialTags.addAll(
|
||||
subspace.tags!.map(
|
||||
(tag) => tag.copyWith(location: subspace.subspaceName),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return initialTags;
|
||||
}
|
||||
}
|
||||
|
@ -13,12 +13,13 @@ import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
class DeviceTypeTileWidget extends StatelessWidget {
|
||||
final ProductModel product;
|
||||
final List<SelectedProduct> productCounts;
|
||||
final bool isCreate;
|
||||
|
||||
const DeviceTypeTileWidget({
|
||||
super.key,
|
||||
const DeviceTypeTileWidget(
|
||||
{super.key,
|
||||
required this.product,
|
||||
required this.productCounts,
|
||||
});
|
||||
required this.isCreate});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -48,7 +49,7 @@ class DeviceTypeTileWidget extends StatelessWidget {
|
||||
DeviceNameWidget(name: product.name),
|
||||
const SizedBox(height: 4),
|
||||
CounterWidget(
|
||||
isCreate: false,
|
||||
isCreate: isCreate,
|
||||
initialCount: selectedProduct.count,
|
||||
onCountChanged: (newCount) {
|
||||
context.read<AddDeviceTypeBloc>().add(
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/bloc/add_device_model_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/bloc/add_device_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/widgets/device_type_tile_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||
@ -9,13 +10,14 @@ class ScrollableGridViewWidget extends StatelessWidget {
|
||||
final List<ProductModel>? products;
|
||||
final int crossAxisCount;
|
||||
final List<SelectedProduct>? initialProductCounts;
|
||||
final bool isCreate;
|
||||
|
||||
const ScrollableGridViewWidget({
|
||||
super.key,
|
||||
const ScrollableGridViewWidget(
|
||||
{super.key,
|
||||
required this.products,
|
||||
required this.crossAxisCount,
|
||||
this.initialProductCounts,
|
||||
});
|
||||
required this.isCreate});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -24,8 +26,11 @@ class ScrollableGridViewWidget extends StatelessWidget {
|
||||
return Scrollbar(
|
||||
controller: scrollController,
|
||||
thumbVisibility: true,
|
||||
child: BlocBuilder<AddDeviceTypeBloc, List<SelectedProduct>>(
|
||||
builder: (context, productCounts) {
|
||||
child: BlocBuilder<AddDeviceTypeBloc, AddDeviceState>(
|
||||
builder: (context, state) {
|
||||
final productCounts = state is AddDeviceLoaded
|
||||
? state.selectedProducts
|
||||
: <SelectedProduct>[];
|
||||
return GridView.builder(
|
||||
controller: scrollController,
|
||||
shrinkWrap: true,
|
||||
@ -42,6 +47,7 @@ class ScrollableGridViewWidget extends StatelessWidget {
|
||||
|
||||
return DeviceTypeTileWidget(
|
||||
product: product,
|
||||
isCreate: isCreate,
|
||||
productCounts: initialProductCount != null
|
||||
? [...productCounts, initialProductCount]
|
||||
: productCounts,
|
||||
|
@ -5,12 +5,15 @@ 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/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/model/subspace_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_body_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart';
|
||||
import 'package:syncrow_web/services/product_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/utils/constants/action_enum.dart';
|
||||
|
||||
class SpaceManagementBloc
|
||||
extends Bloc<SpaceManagementEvent, SpaceManagementState> {
|
||||
@ -341,7 +344,7 @@ class SpaceManagementBloc
|
||||
products: _cachedProducts ?? [],
|
||||
selectedCommunity: selectedCommunity,
|
||||
selectedSpace: selectedSpace,
|
||||
spaceModels: spaceModels ?? []));
|
||||
spaceModels: spaceModels));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(SpaceManagementError('Error updating state: $e'));
|
||||
@ -428,6 +431,76 @@ class SpaceManagementBloc
|
||||
for (var space in orderedSpaces) {
|
||||
try {
|
||||
if (space.uuid != null && space.uuid!.isNotEmpty) {
|
||||
List<TagModelUpdate> tagUpdates = [];
|
||||
|
||||
final prevSpace = await _api.getSpace(communityUuid, space.uuid!);
|
||||
final List<UpdateSubspaceTemplateModel> subspaceUpdates = [];
|
||||
final List<SubspaceModel>? prevSubspaces = prevSpace?.subspaces;
|
||||
final List<SubspaceModel>? newSubspaces = space.subspaces;
|
||||
|
||||
tagUpdates = processTagUpdates(prevSpace?.tags, space.tags);
|
||||
|
||||
if (prevSubspaces != null || newSubspaces != null) {
|
||||
if (prevSubspaces != null && newSubspaces != null) {
|
||||
for (var prevSubspace in prevSubspaces) {
|
||||
final existsInNew = newSubspaces
|
||||
.any((subspace) => subspace.uuid == prevSubspace.uuid);
|
||||
if (!existsInNew) {
|
||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||
action: Action.delete, uuid: prevSubspace.uuid));
|
||||
}
|
||||
}
|
||||
} else if (prevSubspaces != null && newSubspaces == null) {
|
||||
for (var prevSubspace in prevSubspaces) {
|
||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||
action: Action.delete, uuid: prevSubspace.uuid));
|
||||
}
|
||||
}
|
||||
|
||||
if (newSubspaces != null) {
|
||||
for (var newSubspace in newSubspaces) {
|
||||
// Tag without UUID
|
||||
if ((newSubspace.uuid == null || newSubspace.uuid!.isEmpty)) {
|
||||
final List<TagModelUpdate> tagUpdates = [];
|
||||
|
||||
if (newSubspace.tags != null) {
|
||||
for (var tag in newSubspace.tags!) {
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: Action.add,
|
||||
uuid: tag.uuid == '' ? null : tag.uuid,
|
||||
tag: tag.tag,
|
||||
productUuid: tag.product?.uuid));
|
||||
}
|
||||
}
|
||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||
action: Action.add,
|
||||
subspaceName: newSubspace.subspaceName,
|
||||
tags: tagUpdates));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prevSubspaces != null && newSubspaces != null) {
|
||||
final newSubspaceMap = {
|
||||
for (var subspace in newSubspaces) subspace.uuid: subspace
|
||||
};
|
||||
|
||||
for (var prevSubspace in prevSubspaces) {
|
||||
final newSubspace = newSubspaceMap[prevSubspace.uuid];
|
||||
|
||||
if (newSubspace != null) {
|
||||
final List<TagModelUpdate> tagSubspaceUpdates =
|
||||
processTagUpdates(prevSubspace.tags, newSubspace.tags);
|
||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||
action: Action.update,
|
||||
uuid: newSubspace.uuid,
|
||||
subspaceName: newSubspace.subspaceName,
|
||||
tags: tagSubspaceUpdates));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final response = await _api.updateSpace(
|
||||
communityId: communityUuid,
|
||||
spaceId: space.uuid!,
|
||||
@ -436,6 +509,8 @@ class SpaceManagementBloc
|
||||
isPrivate: space.isPrivate,
|
||||
position: space.position,
|
||||
icon: space.icon,
|
||||
subspaces: subspaceUpdates,
|
||||
tags: tagUpdates,
|
||||
direction: space.incomingConnection?.direction,
|
||||
);
|
||||
} else {
|
||||
@ -535,4 +610,79 @@ class SpaceManagementBloc
|
||||
emit(SpaceManagementError('Error loading communities and spaces: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
List<TagModelUpdate> processTagUpdates(
|
||||
List<Tag>? prevTags,
|
||||
List<Tag>? newTags,
|
||||
) {
|
||||
final List<TagModelUpdate> tagUpdates = [];
|
||||
final processedTags = <String?>{};
|
||||
|
||||
if (prevTags == null && newTags != null) {
|
||||
for (var newTag in newTags) {
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: Action.add,
|
||||
tag: newTag.tag,
|
||||
uuid: newTag.uuid,
|
||||
productUuid: newTag.product?.uuid,
|
||||
));
|
||||
}
|
||||
return tagUpdates;
|
||||
}
|
||||
|
||||
if (newTags != null || prevTags != null) {
|
||||
// Case 1: Tags deleted
|
||||
if (prevTags != null && newTags != null) {
|
||||
for (var prevTag in prevTags) {
|
||||
final existsInNew =
|
||||
newTags.any((newTag) => newTag.uuid == prevTag.uuid);
|
||||
if (!existsInNew) {
|
||||
tagUpdates
|
||||
.add(TagModelUpdate(action: Action.delete, uuid: prevTag.uuid));
|
||||
}
|
||||
}
|
||||
} else if (prevTags != null && newTags == null) {
|
||||
for (var prevTag in prevTags) {
|
||||
tagUpdates
|
||||
.add(TagModelUpdate(action: Action.delete, uuid: prevTag.uuid));
|
||||
}
|
||||
}
|
||||
|
||||
// Case 2: Tags added
|
||||
if (newTags != null) {
|
||||
final prevTagUuids = prevTags?.map((t) => t.uuid).toSet() ?? {};
|
||||
|
||||
for (var newTag in newTags) {
|
||||
// Tag without UUID
|
||||
if ((newTag.uuid == null || !prevTagUuids.contains(newTag.uuid)) &&
|
||||
!processedTags.contains(newTag.tag)) {
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: Action.add,
|
||||
tag: newTag.tag,
|
||||
uuid: newTag.uuid == '' ? null : newTag.uuid,
|
||||
productUuid: newTag.product?.uuid));
|
||||
processedTags.add(newTag.tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Case 3: Tags updated
|
||||
if (prevTags != null && newTags != null) {
|
||||
final newTagMap = {for (var tag in newTags) tag.uuid: tag};
|
||||
|
||||
for (var prevTag in prevTags) {
|
||||
final newTag = newTagMap[prevTag.uuid];
|
||||
if (newTag != null) {
|
||||
tagUpdates.add(TagModelUpdate(
|
||||
action: Action.update,
|
||||
uuid: newTag.uuid,
|
||||
tag: newTag.tag,
|
||||
));
|
||||
} else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tagUpdates;
|
||||
}
|
||||
}
|
||||
|
26
lib/pages/spaces_management/all_spaces/model/base_tag.dart
Normal file
26
lib/pages/spaces_management/all_spaces/model/base_tag.dart
Normal file
@ -0,0 +1,26 @@
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
abstract class BaseTag {
|
||||
String? uuid;
|
||||
String? tag;
|
||||
final ProductModel? product;
|
||||
String internalId;
|
||||
String? location;
|
||||
|
||||
BaseTag({
|
||||
this.uuid,
|
||||
required this.tag,
|
||||
this.product,
|
||||
String? internalId,
|
||||
this.location,
|
||||
}) : internalId = internalId ?? const Uuid().v4();
|
||||
|
||||
Map<String, dynamic> toJson();
|
||||
BaseTag copyWith({
|
||||
String? tag,
|
||||
ProductModel? product,
|
||||
String? location,
|
||||
String? internalId,
|
||||
});
|
||||
}
|
@ -66,7 +66,6 @@ class SpaceModel {
|
||||
final instance = SpaceModel(
|
||||
internalId: internalId,
|
||||
uuid: json['uuid'] ?? '',
|
||||
spaceTuyaUuid: json['spaceTuyaUuid'],
|
||||
name: json['spaceName'],
|
||||
isPrivate: json['isPrivate'] ?? false,
|
||||
invitationCode: json['invitationCode'],
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:syncrow_web/utils/constants/action_enum.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'tag.dart';
|
||||
|
||||
@ -8,19 +9,24 @@ class SubspaceModel {
|
||||
String subspaceName;
|
||||
final bool disabled;
|
||||
List<Tag>? tags;
|
||||
String internalId;
|
||||
|
||||
SubspaceModel({
|
||||
this.uuid,
|
||||
required this.subspaceName,
|
||||
required this.disabled,
|
||||
this.tags,
|
||||
});
|
||||
String? internalId,
|
||||
}) : internalId = internalId ?? const Uuid().v4();
|
||||
|
||||
factory SubspaceModel.fromJson(Map<String, dynamic> json) {
|
||||
final String internalId = json['internalId'] ?? const Uuid().v4();
|
||||
|
||||
return SubspaceModel(
|
||||
uuid: json['uuid'] ?? '',
|
||||
subspaceName: json['subspaceName'] ?? '',
|
||||
disabled: json['disabled'] ?? false,
|
||||
internalId: internalId,
|
||||
tags: (json['tags'] as List<dynamic>?)
|
||||
?.map((item) => Tag.fromJson(item))
|
||||
.toList() ??
|
||||
|
@ -1,22 +1,23 @@
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/base_tag.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_body_model.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class Tag {
|
||||
String? uuid;
|
||||
String? tag;
|
||||
final ProductModel? product;
|
||||
String internalId;
|
||||
String? location;
|
||||
|
||||
Tag(
|
||||
{this.uuid,
|
||||
required this.tag,
|
||||
this.product,
|
||||
class Tag extends BaseTag {
|
||||
Tag({
|
||||
String? uuid,
|
||||
required String? tag,
|
||||
ProductModel? product,
|
||||
String? internalId,
|
||||
this.location})
|
||||
: internalId = internalId ?? const Uuid().v4();
|
||||
String? location,
|
||||
}) : super(
|
||||
uuid: uuid,
|
||||
tag: tag,
|
||||
product: product,
|
||||
internalId: internalId,
|
||||
location: location,
|
||||
);
|
||||
|
||||
factory Tag.fromJson(Map<String, dynamic> json) {
|
||||
final String internalId = json['internalId'] ?? const Uuid().v4();
|
||||
@ -31,15 +32,19 @@ class Tag {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Tag copyWith({
|
||||
String? tag,
|
||||
ProductModel? product,
|
||||
String? location,
|
||||
String? internalId,
|
||||
}) {
|
||||
return Tag(
|
||||
uuid: uuid,
|
||||
tag: tag ?? this.tag,
|
||||
product: product ?? this.product,
|
||||
location: location ?? this.location,
|
||||
internalId: internalId ?? this.internalId,
|
||||
);
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user