mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-11-26 10:04:55 +00:00
Compare commits
83 Commits
bugfix/fix
...
SP-1151-FE
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f75ce817e | |||
| aa23daa0b4 | |||
| 61f0c3ad2b | |||
| 27fef7ddaa | |||
| 010176cc25 | |||
| d08a1d1037 | |||
| e634154fb3 | |||
| c0f59aba61 | |||
| 7ee7681e09 | |||
| 57c5f4752c | |||
| ad4f2ae382 | |||
| eafb811d2e | |||
| 2d0dcc41df | |||
| d89e3fac8e | |||
| 25acd67351 | |||
| 0c2a092f4d | |||
| b968b5a6eb | |||
| 05edc7641a | |||
| b8204f1015 | |||
| d87fec796b | |||
| b00b0c82dc | |||
| 0aa029a2fc | |||
| dec3a25639 | |||
| 581dcf7016 | |||
| e1609309cf | |||
| da445e11aa | |||
| 55de7fab0f | |||
| a623f1c723 | |||
| c5f5992c18 | |||
| 98ad7090d8 | |||
| ea08024b82 | |||
| f6d66185b3 | |||
| ead5297ba1 | |||
| 9a6bf5cbaf | |||
| 51fbe64209 | |||
| 49fa80e7d8 | |||
| 1aa15e5dd6 | |||
| 962f2d6861 | |||
| bd6219f915 | |||
| 132cafcaa2 | |||
| 8862ad95f3 | |||
| af4c0f84cb | |||
| c2b77ad1fc | |||
| 95cee89b4c | |||
| d5fcbe2601 | |||
| 1fa33a271f | |||
| 09e2564183 | |||
| 5dee6c2842 | |||
| c5c5088724 | |||
| d1d570b40f | |||
| a43ff3c07d | |||
| 572520eed5 | |||
| 5e5f127a4b | |||
| 6f51c2d2b6 | |||
| a18e8443d0 | |||
| 72241cba6c | |||
| 506531e16a | |||
| ab3edbaf57 | |||
| 5ab9664318 | |||
| d3bf4de0ca | |||
| 5ae07688cb | |||
| e6fa9c2391 | |||
| b070884bd9 | |||
| 7d05a33c52 | |||
| 6e546a4831 | |||
| b098202fd8 | |||
| 43c17d1c18 | |||
| e70b9ea9e2 | |||
| 9e0184f19d | |||
| ea5b6597f5 | |||
| 2221d9ae7b | |||
| 921d352207 | |||
| c5871be990 | |||
| 2fb6f30ccb | |||
| 508d8bbaa8 | |||
| 97bdb1bbb7 | |||
| 7ce0a27af0 | |||
| bc4af6a237 | |||
| 513175ed1e | |||
| 5060d2a66d | |||
| 540f569b1f | |||
| a98f7e77a3 | |||
| 0341844ea9 |
6
assets/icons/delete_space_model.svg
Normal file
6
assets/icons/delete_space_model.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.4 2.10938H11.7333V1.58203C11.7333 0.709699 11.0156 0 10.1333 0H5.86667C4.98443 0 4.26667 0.709699 4.26667 1.58203V2.10938H1.6C0.71776 2.10938 0 2.81907 0 3.69141C0 4.392 0.463111 4.9873 1.1024 5.19472L2.05369 16.5493C2.1222 17.3628 2.82258 18 3.64814 18H12.3519C13.1775 18 13.8778 17.3628 13.9464 16.5491L14.8976 5.19469C15.5369 4.9873 16 4.392 16 3.69141C16 2.81907 15.2822 2.10938 14.4 2.10938ZM5.33333 1.58203C5.33333 1.29125 5.57259 1.05469 5.86667 1.05469H10.1333C10.4274 1.05469 10.6667 1.29125 10.6667 1.58203V2.10938H5.33333V1.58203ZM12.8833 16.4618C12.8605 16.7329 12.6271 16.9453 12.3519 16.9453H3.64814C3.37298 16.9453 3.13952 16.7329 3.11673 16.462L2.17934 5.27344H13.8207L12.8833 16.4618ZM14.4 4.21875H1.6C1.30592 4.21875 1.06667 3.98218 1.06667 3.69141C1.06667 3.40063 1.30592 3.16406 1.6 3.16406H14.4C14.6941 3.16406 14.9333 3.40063 14.9333 3.69141C14.9333 3.98218 14.6941 4.21875 14.4 4.21875Z" fill="#999999"/>
|
||||||
|
<path d="M5.86561 15.3307L5.33228 6.82286C5.31404 6.53215 5.05957 6.31106 4.76698 6.32916C4.47297 6.3472 4.24943 6.59744 4.26764 6.88811L4.80097 15.396C4.8185 15.6756 5.05331 15.8907 5.33278 15.8907C5.64165 15.8907 5.88456 15.6335 5.86561 15.3307Z" fill="#999999"/>
|
||||||
|
<path d="M7.99989 6.32812C7.70534 6.32812 7.46655 6.56423 7.46655 6.85547V15.3633C7.46655 15.6545 7.70534 15.8906 7.99989 15.8906C8.29443 15.8906 8.53322 15.6545 8.53322 15.3633V6.85547C8.53322 6.56423 8.29443 6.32812 7.99989 6.32812Z" fill="#999999"/>
|
||||||
|
<path d="M11.233 6.32915C10.9396 6.31112 10.6859 6.53215 10.6677 6.82285L10.1343 15.3307C10.1162 15.6213 10.3397 15.8716 10.6337 15.8896C10.9278 15.9076 11.1808 15.6865 11.199 15.3959L11.7323 6.8881C11.7505 6.5974 11.527 6.34715 11.233 6.32915Z" fill="#999999"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@ -20,15 +20,22 @@ class DialogTextfieldDropdown extends StatefulWidget {
|
|||||||
|
|
||||||
class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||||
bool _isOpen = false;
|
bool _isOpen = false;
|
||||||
late OverlayEntry _overlayEntry;
|
OverlayEntry? _overlayEntry;
|
||||||
final TextEditingController _controller = TextEditingController();
|
final TextEditingController _controller = TextEditingController();
|
||||||
late List<String> _filteredItems; // Filtered items list
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
List<String> _filteredItems = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller.text = widget.initialValue ?? 'Select Tag';
|
_controller.text = widget.initialValue ?? '';
|
||||||
_filteredItems = List.from(widget.items); // Initialize filtered items
|
_filteredItems = List.from(widget.items);
|
||||||
|
|
||||||
|
_focusNode.addListener(() {
|
||||||
|
if (!_focusNode.hasFocus) {
|
||||||
|
_closeDropdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _toggleDropdown() {
|
void _toggleDropdown() {
|
||||||
@ -41,14 +48,17 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
|
|
||||||
void _openDropdown() {
|
void _openDropdown() {
|
||||||
_overlayEntry = _createOverlayEntry();
|
_overlayEntry = _createOverlayEntry();
|
||||||
Overlay.of(context).insert(_overlayEntry);
|
Overlay.of(context).insert(_overlayEntry!);
|
||||||
_isOpen = true;
|
_isOpen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _closeDropdown() {
|
void _closeDropdown() {
|
||||||
_overlayEntry.remove();
|
if (_isOpen && _overlayEntry != null) {
|
||||||
|
_overlayEntry!.remove();
|
||||||
|
_overlayEntry = null;
|
||||||
_isOpen = false;
|
_isOpen = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OverlayEntry _createOverlayEntry() {
|
OverlayEntry _createOverlayEntry() {
|
||||||
final renderBox = context.findRenderObject() as RenderBox;
|
final renderBox = context.findRenderObject() as RenderBox;
|
||||||
@ -58,9 +68,7 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
return OverlayEntry(
|
return OverlayEntry(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: _closeDropdown,
|
||||||
_closeDropdown();
|
|
||||||
},
|
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.translucent,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
@ -72,14 +80,15 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
elevation: 4.0,
|
elevation: 4.0,
|
||||||
child: Container(
|
child: Container(
|
||||||
color: ColorsManager.whiteColors,
|
color: ColorsManager.whiteColors,
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(maxHeight: 200.0),
|
||||||
maxHeight: 200.0,
|
child: StatefulBuilder(
|
||||||
),
|
builder: (context, setStateDropdown) {
|
||||||
child: ListView.builder(
|
return ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: _filteredItems.length,
|
itemCount: _filteredItems.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = _filteredItems[index];
|
final item = _filteredItems[index];
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
@ -95,7 +104,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
.textTheme
|
.textTheme
|
||||||
.bodyMedium
|
.bodyMedium
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
color: ColorsManager.textPrimaryColor)),
|
color: ColorsManager
|
||||||
|
.textPrimaryColor)),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_controller.text = item;
|
_controller.text = item;
|
||||||
widget.onSelected(item);
|
widget.onSelected(item);
|
||||||
@ -108,6 +118,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -122,7 +134,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: _toggleDropdown,
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -135,23 +148,26 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
onChanged: (value) {
|
focusNode: _focusNode,
|
||||||
setState(() {
|
onFieldSubmitted: (value) {
|
||||||
_filteredItems = widget.items
|
|
||||||
.where((item) =>
|
|
||||||
item.toLowerCase().contains(value.toLowerCase()))
|
|
||||||
.toList(); // Filter items dynamically
|
|
||||||
});
|
|
||||||
widget.onSelected(value);
|
widget.onSelected(value);
|
||||||
|
_closeDropdown();
|
||||||
|
},
|
||||||
|
onTapOutside: (event) {
|
||||||
|
widget.onSelected(_controller.text);
|
||||||
|
_closeDropdown();
|
||||||
},
|
},
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
hintText: 'Enter or Select tag',
|
hintText: 'Enter or Select a tag',
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Icon(Icons.arrow_drop_down),
|
GestureDetector(
|
||||||
|
onTap: _toggleDropdown,
|
||||||
|
child: const Icon(Icons.arrow_drop_down),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -3,18 +3,33 @@ import 'package:flutter_svg/svg.dart';
|
|||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class CustomSearchBar extends StatelessWidget {
|
class CustomSearchBar extends StatefulWidget {
|
||||||
final TextEditingController? controller;
|
final TextEditingController? controller;
|
||||||
final String hintText;
|
final String hintText;
|
||||||
|
final String? searchQuery;
|
||||||
final Function(String)? onSearchChanged; // Callback for search input changes
|
final Function(String)? onSearchChanged; // Callback for search input changes
|
||||||
|
|
||||||
const CustomSearchBar({
|
const CustomSearchBar({
|
||||||
super.key,
|
super.key,
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.searchQuery = '',
|
||||||
this.hintText = 'Search',
|
this.hintText = 'Search',
|
||||||
this.onSearchChanged,
|
this.onSearchChanged,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CustomSearchBar> createState() => _CustomSearchBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomSearchBarState extends State<CustomSearchBar> {
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
if (widget.controller != null) {
|
||||||
|
widget.controller!.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -36,20 +51,20 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: TextField(
|
child: TextFormField(
|
||||||
controller: controller,
|
controller: widget.controller,
|
||||||
|
initialValue: widget.searchQuery,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
onChanged: onSearchChanged, // Call the callback on text change
|
onChanged: widget.onSearchChanged, // Call the callback on text change
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: ColorsManager.textFieldGreyColor,
|
fillColor: ColorsManager.textFieldGreyColor,
|
||||||
hintText: hintText,
|
hintText: widget.hintText,
|
||||||
hintStyle: TextStyle(
|
hintStyle: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
color: Color(0xB2999999),
|
color: ColorsManager.lightGrayColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontFamily: 'Aftika',
|
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
height: 0,
|
height: 0,
|
||||||
letterSpacing: -0.24,
|
letterSpacing: -0.24,
|
||||||
@ -6,17 +6,19 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.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_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_event.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/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||||
import 'package:syncrow_web/services/locator.dart';
|
import 'package:syncrow_web/services/locator.dart';
|
||||||
import 'package:syncrow_web/utils/app_routes.dart';
|
import 'package:syncrow_web/utils/app_routes.dart';
|
||||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||||
import 'package:syncrow_web/utils/theme/theme.dart';
|
import 'package:syncrow_web/utils/theme/theme.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
try {
|
try {
|
||||||
const environment =
|
const environment = String.fromEnvironment('FLAVOR', defaultValue: 'development');
|
||||||
String.fromEnvironment('FLAVOR', defaultValue: 'development');
|
|
||||||
await dotenv.load(fileName: '.env.$environment');
|
await dotenv.load(fileName: '.env.$environment');
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
initialSetup();
|
initialSetup();
|
||||||
@ -25,9 +27,8 @@ Future<void> main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
MyApp({
|
|
||||||
super.key,
|
MyApp({super.key});
|
||||||
});
|
|
||||||
|
|
||||||
final GoRouter _router = GoRouter(
|
final GoRouter _router = GoRouter(
|
||||||
initialLocation: RoutesConst.auth,
|
initialLocation: RoutesConst.auth,
|
||||||
@ -48,14 +49,16 @@ class MyApp extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(
|
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
||||||
create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
|
||||||
BlocProvider<VisitorPasswordBloc>(
|
BlocProvider<VisitorPasswordBloc>(
|
||||||
create: (context) => VisitorPasswordBloc(),
|
create: (context) => VisitorPasswordBloc(),
|
||||||
),
|
),
|
||||||
BlocProvider<RoutineBloc>(
|
BlocProvider<RoutineBloc>(
|
||||||
create: (context) => RoutineBloc(),
|
create: (context) => RoutineBloc(),
|
||||||
),
|
),
|
||||||
|
BlocProvider<SpaceTreeBloc>(
|
||||||
|
create: (context) => SpaceTreeBloc()..add(InitialEvent()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
child: MaterialApp.router(
|
child: MaterialApp.router(
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
@ -67,6 +70,8 @@ class MyApp extends StatelessWidget {
|
|||||||
PointerDeviceKind.unknown,
|
PointerDeviceKind.unknown,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
key: NavigationService.navigatorKey,
|
||||||
|
// scaffoldMessengerKey: NavigationService.snackbarKey,
|
||||||
theme: myTheme,
|
theme: myTheme,
|
||||||
routerConfig: _router,
|
routerConfig: _router,
|
||||||
));
|
));
|
||||||
|
|||||||
@ -3,10 +3,14 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
|
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
|
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
|
||||||
import 'package:syncrow_web/services/access_mang_api.dart';
|
import 'package:syncrow_web/services/access_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||||
|
|
||||||
class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||||
@ -30,8 +34,9 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
Future<void> _onFetchTableData(
|
Future<void> _onFetchTableData(
|
||||||
FetchTableData event, Emitter<AccessState> emit) async {
|
FetchTableData event, Emitter<AccessState> emit) async {
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
emit(AccessLoaded());
|
emit(AccessLoaded());
|
||||||
data = await AccessMangApi().fetchVisitorPassword();
|
data = await AccessMangApi().fetchVisitorPassword(projectUuid);
|
||||||
filteredData = data;
|
filteredData = data;
|
||||||
updateTabsCount();
|
updateTabsCount();
|
||||||
emit(TableLoaded(data));
|
emit(TableLoaded(data));
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
|
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
|
||||||
import 'package:syncrow_web/pages/common/custom_table.dart';
|
import 'package:syncrow_web/pages/common/custom_table.dart';
|
||||||
@ -27,7 +28,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
final isLargeScreen = isLargeScreenSize(context);
|
final isLargeScreen = isLargeScreenSize(context);
|
||||||
final isSmallScreen = isSmallScreenSize(context);
|
final isSmallScreen = isSmallScreenSize(context);
|
||||||
final isHalfMediumScreen = isHafMediumScreenSize(context);
|
final isHalfMediumScreen = isHafMediumScreenSize(context);
|
||||||
final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
final padding =
|
||||||
|
isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
||||||
|
|
||||||
return WebScaffold(
|
return WebScaffold(
|
||||||
enableMenuSidebar: false,
|
enableMenuSidebar: false,
|
||||||
@ -39,7 +41,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
),
|
),
|
||||||
rightBody: const NavigateHomeGridView(),
|
rightBody: const NavigateHomeGridView(),
|
||||||
scaffoldBody: BlocProvider(
|
scaffoldBody: BlocProvider(
|
||||||
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
|
create: (BuildContext context) =>
|
||||||
|
AccessBloc()..add(FetchTableData()),
|
||||||
child: BlocConsumer<AccessBloc, AccessState>(
|
child: BlocConsumer<AccessBloc, AccessState>(
|
||||||
listener: (context, state) {},
|
listener: (context, state) {},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
@ -93,11 +96,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
return [
|
return [
|
||||||
item.passwordName,
|
item.passwordName,
|
||||||
item.passwordType.value,
|
item.passwordType.value,
|
||||||
accessBloc.timestampToDate(item.effectiveTime),
|
accessBloc
|
||||||
accessBloc.timestampToDate(item.invalidTime),
|
.timestampToDate(item.effectiveTime),
|
||||||
|
accessBloc
|
||||||
|
.timestampToDate(item.invalidTime),
|
||||||
item.deviceName.toString(),
|
item.deviceName.toString(),
|
||||||
item.authorizerEmail.toString(),
|
item.authorizerEmail.toString(),
|
||||||
accessBloc.timestampToDate(item.invalidTime),
|
accessBloc
|
||||||
|
.timestampToDate(item.invalidTime),
|
||||||
item.passwordStatus.value,
|
item.passwordStatus.value,
|
||||||
];
|
];
|
||||||
}).toList(),
|
}).toList(),
|
||||||
@ -108,7 +114,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
Wrap _buildVisitorAdminPasswords(BuildContext context, AccessBloc accessBloc) {
|
Wrap _buildVisitorAdminPasswords(
|
||||||
|
BuildContext context, AccessBloc accessBloc) {
|
||||||
return Wrap(
|
return Wrap(
|
||||||
spacing: 10,
|
spacing: 10,
|
||||||
runSpacing: 10,
|
runSpacing: 10,
|
||||||
@ -134,7 +141,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Create Visitor Password ',
|
'Create Visitor Password ',
|
||||||
style: context.textTheme.titleSmall!.copyWith(color: Colors.white, fontSize: 12),
|
style: context.textTheme.titleSmall!
|
||||||
|
.copyWith(color: Colors.white, fontSize: 12),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
// Container(
|
// Container(
|
||||||
@ -172,8 +180,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
description: '',
|
description: '',
|
||||||
onSubmitted: (value) {
|
onSubmitted: (value) {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer:
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
@ -191,8 +201,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
description: '',
|
description: '',
|
||||||
onSubmitted: (value) {
|
onSubmitted: (value) {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer:
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
@ -221,7 +233,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
onSearch: () {
|
onSearch: () {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
@ -249,8 +262,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
description: '',
|
description: '',
|
||||||
onSubmitted: (value) {
|
onSubmitted: (value) {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer:
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
@ -274,7 +289,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
onSearch: () {
|
onSearch: () {
|
||||||
accessBloc.add(FilterDataEvent(
|
accessBloc.add(FilterDataEvent(
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
|
|||||||
@ -9,9 +9,13 @@ import 'package:syncrow_web/pages/auth/model/login_with_email_model.dart';
|
|||||||
import 'package:syncrow_web/pages/auth/model/region_model.dart';
|
import 'package:syncrow_web/pages/auth/model/region_model.dart';
|
||||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
import 'package:syncrow_web/pages/auth/model/token.dart';
|
||||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.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/services/auth_api.dart';
|
import 'package:syncrow_web/services/auth_api.dart';
|
||||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
|
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||||
|
|
||||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||||
@ -161,8 +165,14 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
password: event.password,
|
password: event.password,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (failure) {
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['error']['message'];
|
||||||
|
if (errorMessage == "Access denied for web platform") {
|
||||||
|
validate = errorMessage;
|
||||||
|
} else {
|
||||||
validate = 'Invalid Credentials!';
|
validate = 'Invalid Credentials!';
|
||||||
|
}
|
||||||
emit(LoginInitial());
|
emit(LoginInitial());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -176,7 +186,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
user = UserModel.fromToken(token);
|
user = UserModel.fromToken(token);
|
||||||
loginEmailController.clear();
|
loginEmailController.clear();
|
||||||
loginPasswordController.clear();
|
loginPasswordController.clear();
|
||||||
debugPrint("token " + token.accessToken);
|
|
||||||
emit(LoginSuccess());
|
emit(LoginSuccess());
|
||||||
} else {
|
} else {
|
||||||
emit(const LoginFailure(error: 'Something went wrong'));
|
emit(const LoginFailure(error: 'Something went wrong'));
|
||||||
@ -423,8 +432,10 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
emit(LoginInitial());
|
emit(LoginInitial());
|
||||||
}
|
}
|
||||||
|
|
||||||
static logout() {
|
static Future<void> logout(BuildContext context) async {
|
||||||
const storage = FlutterSecureStorage();
|
final storage = FlutterSecureStorage();
|
||||||
|
ProjectManager.clearProjectUUID();
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearAllData());
|
||||||
storage.deleteAll();
|
storage.deleteAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,9 @@ class LoginWithEmailModel {
|
|||||||
return {
|
return {
|
||||||
'email': email,
|
'email': email,
|
||||||
'password': password,
|
'password': password,
|
||||||
|
"platform": "web"
|
||||||
// 'regionUuid': regionUuid,
|
// 'regionUuid': regionUuid,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//tst@tst.com
|
||||||
27
lib/pages/auth/model/project_model.dart
Normal file
27
lib/pages/auth/model/project_model.dart
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
class Project {
|
||||||
|
final String uuid;
|
||||||
|
final String name;
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
const Project({
|
||||||
|
required this.uuid,
|
||||||
|
required this.name,
|
||||||
|
required this.description,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Project.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Project(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
name: json['name'] as String,
|
||||||
|
description: json['description'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'name': name,
|
||||||
|
'description': description,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:syncrow_web/pages/auth/model/project_model.dart';
|
||||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
import 'package:syncrow_web/pages/auth/model/token.dart';
|
||||||
|
|
||||||
class UserModel {
|
class UserModel {
|
||||||
@ -10,6 +11,11 @@ class UserModel {
|
|||||||
final String? phoneNumber;
|
final String? phoneNumber;
|
||||||
final bool? isEmailVerified;
|
final bool? isEmailVerified;
|
||||||
final bool? isAgreementAccepted;
|
final bool? isAgreementAccepted;
|
||||||
|
final bool? hasAcceptedWebAgreement;
|
||||||
|
final DateTime? webAgreementAcceptedAt;
|
||||||
|
final UserRole? role;
|
||||||
|
final Project? project;
|
||||||
|
|
||||||
UserModel({
|
UserModel({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
required this.email,
|
required this.email,
|
||||||
@ -19,6 +25,10 @@ class UserModel {
|
|||||||
required this.phoneNumber,
|
required this.phoneNumber,
|
||||||
required this.isEmailVerified,
|
required this.isEmailVerified,
|
||||||
required this.isAgreementAccepted,
|
required this.isAgreementAccepted,
|
||||||
|
required this.hasAcceptedWebAgreement,
|
||||||
|
required this.webAgreementAcceptedAt,
|
||||||
|
required this.role,
|
||||||
|
required this.project,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory UserModel.fromJson(Map<String, dynamic> json) {
|
factory UserModel.fromJson(Map<String, dynamic> json) {
|
||||||
@ -31,6 +41,13 @@ class UserModel {
|
|||||||
phoneNumber: json['phoneNumber'],
|
phoneNumber: json['phoneNumber'],
|
||||||
isEmailVerified: json['isEmailVerified'],
|
isEmailVerified: json['isEmailVerified'],
|
||||||
isAgreementAccepted: json['isAgreementAccepted'],
|
isAgreementAccepted: json['isAgreementAccepted'],
|
||||||
|
hasAcceptedWebAgreement: json['hasAcceptedWebAgreement'],
|
||||||
|
webAgreementAcceptedAt: json['webAgreementAcceptedAt'] != null
|
||||||
|
? DateTime.parse(json['webAgreementAcceptedAt'])
|
||||||
|
: null,
|
||||||
|
role: json['role'] != null ? UserRole.fromJson(json['role']) : null,
|
||||||
|
project:
|
||||||
|
json['project'] != null ? Project.fromJson(json['project']) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +58,9 @@ class UserModel {
|
|||||||
Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken);
|
Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken);
|
||||||
|
|
||||||
return UserModel(
|
return UserModel(
|
||||||
|
hasAcceptedWebAgreement: null,
|
||||||
|
role: null,
|
||||||
|
webAgreementAcceptedAt: null,
|
||||||
uuid: tempJson['uuid'].toString(),
|
uuid: tempJson['uuid'].toString(),
|
||||||
email: tempJson['email'],
|
email: tempJson['email'],
|
||||||
firstName: null,
|
firstName: null,
|
||||||
@ -49,6 +69,7 @@ class UserModel {
|
|||||||
phoneNumber: null,
|
phoneNumber: null,
|
||||||
isEmailVerified: null,
|
isEmailVerified: null,
|
||||||
isAgreementAccepted: null,
|
isAgreementAccepted: null,
|
||||||
|
project: null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,3 +86,26 @@ class UserModel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UserRole {
|
||||||
|
final String uuid;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final String type;
|
||||||
|
|
||||||
|
UserRole({
|
||||||
|
required this.uuid,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.type,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory UserRole.fromJson(Map<String, dynamic> json) {
|
||||||
|
return UserRole(
|
||||||
|
uuid: json['uuid'],
|
||||||
|
createdAt: DateTime.parse(json['createdAt']),
|
||||||
|
updatedAt: DateTime.parse(json['updatedAt']),
|
||||||
|
type: json['type'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
19
lib/pages/common/bloc/project_manager.dart
Normal file
19
lib/pages/common/bloc/project_manager.dart
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
|
|
||||||
|
class ProjectManager {
|
||||||
|
static Future<String?> getProjectUUID() async {
|
||||||
|
final projectUuid = await SharedPreferencesHelper.readStringFromSP(
|
||||||
|
StringsManager.projectKey);
|
||||||
|
return projectUuid.isNotEmpty ? projectUuid : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> setProjectUUID(String newUUID) async {
|
||||||
|
await SharedPreferencesHelper.saveStringToSP(
|
||||||
|
StringsManager.projectKey, newUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> clearProjectUUID() async {
|
||||||
|
await SharedPreferencesHelper.removeValueFromSP(StringsManager.projectKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,13 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.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';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
|
|
||||||
part 'device_managment_event.dart';
|
part 'device_managment_event.dart';
|
||||||
part 'device_managment_state.dart';
|
part 'device_managment_state.dart';
|
||||||
@ -34,7 +40,25 @@ class DeviceManagementBloc
|
|||||||
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||||
emit(DeviceManagementLoading());
|
emit(DeviceManagementLoading());
|
||||||
try {
|
try {
|
||||||
final devices = await DevicesManagementApi().fetchDevices();
|
List<AllDevicesModel> devices = [];
|
||||||
|
_devices.clear();
|
||||||
|
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
||||||
|
devices = await DevicesManagementApi()
|
||||||
|
.fetchDevices('', '', projectUuid );
|
||||||
|
} 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, projectUuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_selectedDevices.clear();
|
_selectedDevices.clear();
|
||||||
_devices = devices;
|
_devices = devices;
|
||||||
_filteredDevices = devices;
|
_filteredDevices = devices;
|
||||||
@ -288,8 +312,8 @@ class DeviceManagementBloc
|
|||||||
event.unitName!.isEmpty ||
|
event.unitName!.isEmpty ||
|
||||||
(device.spaces != null &&
|
(device.spaces != null &&
|
||||||
device.spaces!.isNotEmpty &&
|
device.spaces!.isNotEmpty &&
|
||||||
device.spaces![0].spaceName
|
device.spaces![0].spaceName!
|
||||||
!.toLowerCase()
|
.toLowerCase()
|
||||||
.contains(event.unitName!.toLowerCase()));
|
.contains(event.unitName!.toLowerCase()));
|
||||||
final matchesProductName = event.productName == null ||
|
final matchesProductName = event.productName == null ||
|
||||||
event.productName!.isEmpty ||
|
event.productName!.isEmpty ||
|
||||||
|
|||||||
@ -7,7 +7,15 @@ abstract class DeviceManagementEvent extends Equatable {
|
|||||||
List<Object?> get props => [];
|
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 {
|
class FilterDevices extends DeviceManagementEvent {
|
||||||
final String filter;
|
final String filter;
|
||||||
|
|||||||
@ -3,11 +3,11 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_spa
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_subspace.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/room.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.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/routines/models/ac/ac_function.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/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/routines/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/routines/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/gang_switches/two_gang_switch/two_gang_switch.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/enum/device_types.dart';
|
import 'package:syncrow_web/utils/enum/device_types.dart';
|
||||||
|
|
||||||
@ -148,9 +148,7 @@ class AllDevicesModel {
|
|||||||
|
|
||||||
productName = json['productName']?.toString();
|
productName = json['productName']?.toString();
|
||||||
if (json['spaces'] != null && json['spaces'] is List) {
|
if (json['spaces'] != null && json['spaces'] is List) {
|
||||||
spaces = (json['spaces'] as List)
|
spaces = (json['spaces'] as List).map((space) => DeviceSpaceModel.fromJson(space)).toList();
|
||||||
.map((space) => DeviceSpaceModel.fromJson(space))
|
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,8 +196,7 @@ SOS
|
|||||||
String tempIcon = '';
|
String tempIcon = '';
|
||||||
if (type == DeviceType.LightBulb) {
|
if (type == DeviceType.LightBulb) {
|
||||||
tempIcon = Assets.lightBulb;
|
tempIcon = Assets.lightBulb;
|
||||||
} else if (type == DeviceType.CeilingSensor ||
|
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
|
||||||
type == DeviceType.WallSensor) {
|
|
||||||
tempIcon = Assets.sensors;
|
tempIcon = Assets.sensors;
|
||||||
} else if (type == DeviceType.AC) {
|
} else if (type == DeviceType.AC) {
|
||||||
tempIcon = Assets.ac;
|
tempIcon = Assets.ac;
|
||||||
@ -254,34 +251,25 @@ SOS
|
|||||||
case '1G':
|
case '1G':
|
||||||
return [
|
return [
|
||||||
OneGangSwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
OneGangSwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
OneGangCountdownFunction(
|
OneGangCountdownFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
case '2G':
|
case '2G':
|
||||||
return [
|
return [
|
||||||
TwoGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
TwoGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
TwoGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
TwoGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
TwoGangCountdown1Function(
|
TwoGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
TwoGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
TwoGangCountdown2Function(
|
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
case '3G':
|
case '3G':
|
||||||
return [
|
return [
|
||||||
ThreeGangSwitch1Function(
|
ThreeGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
ThreeGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
ThreeGangSwitch2Function(
|
ThreeGangSwitch3Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
ThreeGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
ThreeGangSwitch3Function(
|
ThreeGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
ThreeGangCountdown3Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||||
ThreeGangCountdown1Function(
|
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
ThreeGangCountdown2Function(
|
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
ThreeGangCountdown3Function(
|
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.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/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/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/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/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
|
import 'package:syncrow_web/pages/routines/view/create_new_routine_view.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/view/routines_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/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
@ -19,7 +20,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => DeviceManagementBloc()..add(FetchDevices()),
|
create: (context) =>
|
||||||
|
DeviceManagementBloc()..add(FetchDevices(context)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: WebScaffold(
|
child: WebScaffold(
|
||||||
@ -41,6 +43,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
context
|
context
|
||||||
.read<RoutineBloc>()
|
.read<RoutineBloc>()
|
||||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
||||||
|
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Devices',
|
'Devices',
|
||||||
@ -80,7 +83,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||||
builder: (context, deviceState) {
|
builder: (context, deviceState) {
|
||||||
if (deviceState is DeviceManagementLoading) {
|
if (deviceState is DeviceManagementLoading) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const DeviceManagementBody(devices: []);
|
||||||
} else if (deviceState is DeviceManagementLoaded) {
|
} else if (deviceState is DeviceManagementLoaded) {
|
||||||
return DeviceManagementBody(devices: deviceState.devices);
|
return DeviceManagementBody(devices: deviceState.devices);
|
||||||
} else if (deviceState is DeviceManagementFiltered) {
|
} 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/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_batch_control_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/device_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/format_date_time.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
import 'package:syncrow_web/utils/style.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';
|
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: [
|
children: [
|
||||||
Container(
|
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(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -71,7 +86,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
tabs: tabs,
|
tabs: tabs,
|
||||||
selectedIndex: selectedIndex,
|
selectedIndex: selectedIndex,
|
||||||
onTabChanged: (index) {
|
onTabChanged: (index) {
|
||||||
context.read<DeviceManagementBloc>().add(SelectedFilterChanged(index));
|
context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.add(SelectedFilterChanged(index));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
@ -93,7 +110,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (selectedDevices.length > 1) {
|
} 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) {
|
if (productTypes.length == 1) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -122,13 +141,17 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
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(
|
child: DynamicTable(
|
||||||
withSelectAll: true,
|
withSelectAll: true,
|
||||||
cellDecoration: containerDecoration,
|
cellDecoration: containerDecoration,
|
||||||
onRowSelected: (index, isSelected, row) {
|
onRowSelected: (index, isSelected, row) {
|
||||||
final selectedDevice = devicesToShow[index];
|
final selectedDevice = devicesToShow[index];
|
||||||
context.read<DeviceManagementBloc>().add(SelectDevice(selectedDevice));
|
context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.add(SelectDevice(selectedDevice));
|
||||||
},
|
},
|
||||||
withCheckBox: true,
|
withCheckBox: true,
|
||||||
size: MediaQuery.of(context).size,
|
size: MediaQuery.of(context).size,
|
||||||
@ -147,31 +170,45 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
data: devicesToShow.map((device) {
|
data: devicesToShow.map((device) {
|
||||||
final combinedSpaceNames = device.spaces != null
|
final combinedSpaceNames = device.spaces != null
|
||||||
? device.spaces!.map((space) => space.spaceName).join(' > ') +
|
? 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 : '');
|
: (device.community != null ? device.community!.name : '');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
device.name ?? '',
|
device.name ?? '',
|
||||||
device.productName ?? '',
|
device.productName ?? '',
|
||||||
device.uuid ?? '',
|
device.uuid ?? '',
|
||||||
(device.spaces != null && device.spaces!.isNotEmpty) ? device.spaces![0].spaceName : '',
|
(device.spaces != null && device.spaces!.isNotEmpty)
|
||||||
|
? device.spaces![0].spaceName
|
||||||
|
: '',
|
||||||
combinedSpaceNames,
|
combinedSpaceNames,
|
||||||
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
||||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
|
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(device.createTime ?? 0) * 1000)),
|
||||||
device.online == true ? 'Online' : 'Offline',
|
device.online == true ? 'Online' : 'Offline',
|
||||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
|
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(device.updateTime ?? 0) * 1000)),
|
||||||
];
|
];
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onSelectionChanged: (selectedRows) {
|
onSelectionChanged: (selectedRows) {
|
||||||
context.read<DeviceManagementBloc>().add(UpdateSelection(selectedRows));
|
context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.add(UpdateSelection(selectedRows));
|
||||||
},
|
},
|
||||||
initialSelectedIds:
|
initialSelectedIds: context
|
||||||
context.read<DeviceManagementBloc>().selectedDevices.map((device) => device.uuid!).toList(),
|
.read<DeviceManagementBloc>()
|
||||||
|
.selectedDevices
|
||||||
|
.map((device) => device.uuid!)
|
||||||
|
.toList(),
|
||||||
isEmpty: devicesToShow.isEmpty,
|
isEmpty: devicesToShow.isEmpty,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -12,8 +12,7 @@ class DeviceSearchFilters extends StatefulWidget {
|
|||||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
||||||
with HelperResponsiveLayout {
|
|
||||||
final TextEditingController communityController = TextEditingController();
|
final TextEditingController communityController = TextEditingController();
|
||||||
final TextEditingController unitNameController = TextEditingController();
|
final TextEditingController unitNameController = TextEditingController();
|
||||||
final TextEditingController productNameController = TextEditingController();
|
final TextEditingController productNameController = TextEditingController();
|
||||||
@ -27,8 +26,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
|||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
_buildSearchField("Space Name", unitNameController, 200),
|
_buildSearchField("Space Name", unitNameController, 200),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
_buildSearchField(
|
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
||||||
"Device Name / Product Name", productNameController, 300),
|
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
_buildSearchResetButtons(),
|
_buildSearchResetButtons(),
|
||||||
],
|
],
|
||||||
@ -53,8 +51,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchField(
|
Widget _buildSearchField(String title, TextEditingController controller, double width) {
|
||||||
String title, TextEditingController controller, double width) {
|
|
||||||
return Container(
|
return Container(
|
||||||
child: StatefulTextField(
|
child: StatefulTextField(
|
||||||
title: title,
|
title: title,
|
||||||
@ -88,7 +85,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
|||||||
productNameController.clear();
|
productNameController.clear();
|
||||||
context.read<DeviceManagementBloc>()
|
context.read<DeviceManagementBloc>()
|
||||||
..add(ResetFilters())
|
..add(ResetFilters())
|
||||||
..add(FetchDevices());
|
..add(FetchDevices(context));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,56 +1,108 @@
|
|||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:graphview/GraphView.dart';
|
|
||||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_event.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/bloc/home_state.dart';
|
||||||
import 'package:syncrow_web/pages/home/home_model/home_item_model.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/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||||
import 'package:syncrow_web/services/home_api.dart';
|
import 'package:syncrow_web/services/home_api.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||||
|
|
||||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||||
final Graph graph = Graph()..isTree = true;
|
// final Graph graph = Graph()..isTree = true;
|
||||||
final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
// final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
||||||
List<Node> sourcesList = [];
|
// List<Node> sourcesList = [];
|
||||||
List<Node> destinationsList = [];
|
// List<Node> destinationsList = [];
|
||||||
UserModel? user;
|
UserModel? user;
|
||||||
|
String terms = '';
|
||||||
|
String policy = '';
|
||||||
|
|
||||||
HomeBloc() : super((HomeInitial())) {
|
HomeBloc() : super((HomeInitial())) {
|
||||||
on<CreateNewNode>(_createNode);
|
// on<CreateNewNode>(_createNode);
|
||||||
on<FetchUserInfo>(_fetchUserInfo);
|
on<FetchUserInfo>(_fetchUserInfo);
|
||||||
|
on<FetchTermEvent>(_fetchTerms);
|
||||||
|
on<FetchPolicyEvent>(_fetchPolicy);
|
||||||
|
on<ConfirmUserAgreementEvent>(_confirmUserAgreement);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
// void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
||||||
emit(HomeInitial());
|
// emit(HomeInitial());
|
||||||
sourcesList.add(event.sourceNode);
|
// sourcesList.add(event.sourceNode);
|
||||||
destinationsList.add(event.destinationNode);
|
// destinationsList.add(event.destinationNode);
|
||||||
for (int i = 0; i < sourcesList.length; i++) {
|
// for (int i = 0; i < sourcesList.length; i++) {
|
||||||
graph.addEdge(sourcesList[i], destinationsList[i]);
|
// graph.addEdge(sourcesList[i], destinationsList[i]);
|
||||||
}
|
// }
|
||||||
|
|
||||||
builder
|
// builder
|
||||||
..siblingSeparation = (100)
|
// ..siblingSeparation = (100)
|
||||||
..levelSeparation = (150)
|
// ..levelSeparation = (150)
|
||||||
..subtreeSeparation = (150)
|
// ..subtreeSeparation = (150)
|
||||||
..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
|
// ..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
|
||||||
emit(HomeUpdateTree(graph: graph, builder: builder));
|
// emit(HomeUpdateTree(graph: graph, builder: builder));
|
||||||
}
|
// }
|
||||||
|
|
||||||
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
||||||
try {
|
try {
|
||||||
var uuid =
|
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
|
||||||
user = await HomeApi().fetchUserInfo(uuid);
|
user = await HomeApi().fetchUserInfo(uuid);
|
||||||
|
|
||||||
|
if (user != null && user!.project != null) {
|
||||||
|
await ProjectManager.setProjectUUID(user!.project!.uuid);
|
||||||
|
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>().add(InitialEvent());
|
||||||
|
}
|
||||||
|
add(FetchTermEvent());
|
||||||
|
add(FetchPolicyEvent());
|
||||||
|
|
||||||
emit(HomeInitial());
|
emit(HomeInitial());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future _fetchTerms(FetchTermEvent event, Emitter<HomeState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(LoadingHome());
|
||||||
|
terms = await HomeApi().fetchTerms();
|
||||||
|
emit(HomeInitial());
|
||||||
|
|
||||||
|
// emit(PolicyAgreement());
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _fetchPolicy(FetchPolicyEvent event, Emitter<HomeState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(LoadingHome());
|
||||||
|
policy = await HomeApi().fetchPolicy();
|
||||||
|
debugPrint("Fetched policy: $policy");
|
||||||
|
// Emit a state to trigger the UI update
|
||||||
|
emit(HomeInitial());
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Error fetching policy: $e");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _confirmUserAgreement(ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(LoadingHome());
|
||||||
|
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
|
policy = await HomeApi().confirmUserAgreements(uuid);
|
||||||
|
emit(PolicyAgreement());
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// static Future fetchUserInfo() async {
|
// static Future fetchUserInfo() async {
|
||||||
// try {
|
// try {
|
||||||
// var uuid =
|
// var uuid =
|
||||||
@ -67,6 +119,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
icon: Assets.accessIcon,
|
icon: Assets.accessIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||||
context.go(RoutesConst.accessManagementPage);
|
context.go(RoutesConst.accessManagementPage);
|
||||||
},
|
},
|
||||||
color: null,
|
color: null,
|
||||||
@ -76,6 +129,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
icon: Assets.spaseManagementIcon,
|
icon: Assets.spaseManagementIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||||
context.go(RoutesConst.spacesManagementPage);
|
context.go(RoutesConst.spacesManagementPage);
|
||||||
},
|
},
|
||||||
color: ColorsManager.primaryColor,
|
color: ColorsManager.primaryColor,
|
||||||
@ -85,6 +139,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
icon: Assets.devicesIcon,
|
icon: Assets.devicesIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
|
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||||
BlocProvider.of<RoutineBloc>(context)
|
BlocProvider.of<RoutineBloc>(context)
|
||||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
||||||
context.go(RoutesConst.deviceManagementPage);
|
context.go(RoutesConst.deviceManagementPage);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:graphview/GraphView.dart';
|
// import 'package:graphview/GraphView.dart';
|
||||||
|
|
||||||
abstract class HomeEvent extends Equatable {
|
abstract class HomeEvent extends Equatable {
|
||||||
const HomeEvent();
|
const HomeEvent();
|
||||||
@ -8,16 +8,22 @@ abstract class HomeEvent extends Equatable {
|
|||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateNewNode extends HomeEvent {
|
// class CreateNewNode extends HomeEvent {
|
||||||
final Node sourceNode;
|
// final Node sourceNode;
|
||||||
final Node destinationNode;
|
// final Node destinationNode;
|
||||||
const CreateNewNode(
|
// const CreateNewNode(
|
||||||
{required this.sourceNode, required this.destinationNode});
|
// {required this.sourceNode, required this.destinationNode});
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
List<Object> get props => [sourceNode, destinationNode];
|
// List<Object> get props => [sourceNode, destinationNode];
|
||||||
}
|
// }
|
||||||
|
|
||||||
class FetchUserInfo extends HomeEvent {
|
class FetchUserInfo extends HomeEvent {
|
||||||
const FetchUserInfo();
|
const FetchUserInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FetchTermEvent extends HomeEvent {}
|
||||||
|
|
||||||
|
class FetchPolicyEvent extends HomeEvent {}
|
||||||
|
|
||||||
|
class ConfirmUserAgreementEvent extends HomeEvent {}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:graphview/GraphView.dart';
|
// import 'package:graphview/GraphView.dart';
|
||||||
|
|
||||||
abstract class HomeState extends Equatable {
|
abstract class HomeState extends Equatable {
|
||||||
const HomeState();
|
const HomeState();
|
||||||
@ -8,19 +8,25 @@ abstract class HomeState extends Equatable {
|
|||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LoadingHome extends HomeState {}
|
||||||
|
|
||||||
class HomeInitial extends HomeState {}
|
class HomeInitial extends HomeState {}
|
||||||
|
|
||||||
class HomeCounterState extends HomeState {
|
class TermsAgreement extends HomeState {}
|
||||||
final int counter;
|
|
||||||
const HomeCounterState(this.counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
class HomeUpdateTree extends HomeState {
|
class PolicyAgreement extends HomeState {}
|
||||||
final Graph graph;
|
|
||||||
final BuchheimWalkerConfiguration builder;
|
|
||||||
|
|
||||||
const HomeUpdateTree({required this.graph, required this.builder});
|
// class HomeCounterState extends HomeState {
|
||||||
|
// final int counter;
|
||||||
|
// const HomeCounterState(this.counter);
|
||||||
|
// }
|
||||||
|
|
||||||
@override
|
// class HomeUpdateTree extends HomeState {
|
||||||
List<Object> get props => [graph, builder];
|
// final Graph graph;
|
||||||
}
|
// final BuchheimWalkerConfiguration builder;
|
||||||
|
|
||||||
|
// const HomeUpdateTree({required this.graph, required this.builder});
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// List<Object> get props => [graph, builder];
|
||||||
|
// }
|
||||||
|
|||||||
180
lib/pages/home/view/agreement_and_privacy_dialog.dart
Normal file
180
lib/pages/home/view/agreement_and_privacy_dialog.dart
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class AgreementAndPrivacyDialog extends StatefulWidget {
|
||||||
|
final String terms;
|
||||||
|
final String policy;
|
||||||
|
|
||||||
|
const AgreementAndPrivacyDialog({
|
||||||
|
super.key,
|
||||||
|
required this.terms,
|
||||||
|
required this.policy,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_AgreementAndPrivacyDialogState createState() =>
|
||||||
|
_AgreementAndPrivacyDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AgreementAndPrivacyDialogState extends State<AgreementAndPrivacyDialog> {
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
bool _isAtEnd = false;
|
||||||
|
int _currentPage = 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_scrollController.addListener(_onScroll);
|
||||||
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) => _checkScrollRequirement());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkScrollRequirement() {
|
||||||
|
final scrollPosition = _scrollController.position;
|
||||||
|
if (scrollPosition.maxScrollExtent <= 0) {
|
||||||
|
setState(() {
|
||||||
|
_isAtEnd = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.removeListener(_onScroll);
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onScroll() {
|
||||||
|
if (_scrollController.position.atEdge) {
|
||||||
|
final isAtBottom = _scrollController.position.pixels ==
|
||||||
|
_scrollController.position.maxScrollExtent;
|
||||||
|
if (isAtBottom && !_isAtEnd) {
|
||||||
|
setState(() {
|
||||||
|
_isAtEnd = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String get _dialogTitle =>
|
||||||
|
_currentPage == 1 ? 'User Agreement' : 'Privacy Policy';
|
||||||
|
|
||||||
|
String get _dialogContent => _currentPage == 1 ? widget.terms : widget.policy;
|
||||||
|
final String staticText =
|
||||||
|
'<h5 style="color: #FF5722;">If you cancel you will be logged out.</h5>';
|
||||||
|
|
||||||
|
Widget _buildScrollableContent() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(40),
|
||||||
|
width: MediaQuery.of(context).size.width * 0.8,
|
||||||
|
height: MediaQuery.of(context).size.height * 0.75,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[200],
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
|
),
|
||||||
|
child: Scrollbar(
|
||||||
|
thumbVisibility: true,
|
||||||
|
trackVisibility: true,
|
||||||
|
interactive: true,
|
||||||
|
controller: _scrollController,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: _scrollController,
|
||||||
|
padding: const EdgeInsets.all(25),
|
||||||
|
child: Html(
|
||||||
|
data: "$_dialogContent $staticText",
|
||||||
|
onLinkTap: (url, attributes, element) async {
|
||||||
|
if (url != null) {
|
||||||
|
final uri = Uri.parse(url);
|
||||||
|
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
"body": Style(
|
||||||
|
fontSize: FontSize(14),
|
||||||
|
color: Colors.black87,
|
||||||
|
lineHeight: LineHeight(1.5),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildActionButton() {
|
||||||
|
final String buttonText = _currentPage == 2 ? "I Agree" : "Next";
|
||||||
|
|
||||||
|
return InkWell(
|
||||||
|
onTap: _isAtEnd
|
||||||
|
? () {
|
||||||
|
if (_currentPage == 1) {
|
||||||
|
setState(() {
|
||||||
|
_currentPage = 2;
|
||||||
|
_isAtEnd = false;
|
||||||
|
_scrollController.jumpTo(0);
|
||||||
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) => _checkScrollRequirement());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: Text(
|
||||||
|
buttonText,
|
||||||
|
style: TextStyle(
|
||||||
|
color: _isAtEnd ? ColorsManager.secondaryColor : Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Dialog(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Text(
|
||||||
|
_dialogTitle,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: ColorsManager.secondaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
_buildScrollableContent(),
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
AuthBloc.logout(context);
|
||||||
|
context.go(RoutesConst.auth);
|
||||||
|
},
|
||||||
|
child: const Text("Cancel"),
|
||||||
|
),
|
||||||
|
_buildActionButton(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -41,8 +41,7 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
SizedBox(height: size.height * 0.05),
|
SizedBox(height: size.height * 0.05),
|
||||||
const Text(
|
const Text(
|
||||||
'ACCESS YOUR APPS',
|
'ACCESS YOUR APPS',
|
||||||
style:
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
|
||||||
TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -51,9 +50,8 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
height: size.height * 0.6,
|
height: size.height * 0.6,
|
||||||
width: size.width * 0.68,
|
width: size.width * 0.68,
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
itemCount: 8,
|
itemCount: 3,
|
||||||
gridDelegate:
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 2,
|
crossAxisCount: 2,
|
||||||
crossAxisSpacing: 20.0,
|
crossAxisSpacing: 20.0,
|
||||||
mainAxisSpacing: 20.0,
|
mainAxisSpacing: 20.0,
|
||||||
@ -65,8 +63,7 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
active: homeItems[index]['active'],
|
active: homeItems[index]['active'],
|
||||||
name: homeItems[index]['title'],
|
name: homeItems[index]['title'],
|
||||||
img: homeItems[index]['icon'],
|
img: homeItems[index]['icon'],
|
||||||
onTap: () =>
|
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||||
homeBloc.homeItems[index].onPress(context),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -97,33 +94,33 @@ class HomeMobilePage extends StatelessWidget {
|
|||||||
'icon': Assets.devicesIcon,
|
'icon': Assets.devicesIcon,
|
||||||
'active': true,
|
'active': true,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
'title': 'Move in',
|
// 'title': 'Move in',
|
||||||
'icon': Assets.moveinIcon,
|
// 'icon': Assets.moveinIcon,
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
'title': 'Construction',
|
// 'title': 'Construction',
|
||||||
'icon': Assets.constructionIcon,
|
// 'icon': Assets.constructionIcon,
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
'title': 'Energy',
|
// 'title': 'Energy',
|
||||||
'icon': Assets.energyIcon,
|
// 'icon': Assets.energyIcon,
|
||||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
'title': 'Integrations',
|
// 'title': 'Integrations',
|
||||||
'icon': Assets.integrationsIcon,
|
// 'icon': Assets.integrationsIcon,
|
||||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
'title': 'Asset',
|
// 'title': 'Asset',
|
||||||
'icon': Assets.assetIcon,
|
// 'icon': Assets.assetIcon,
|
||||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
'active': false,
|
// 'active': false,
|
||||||
},
|
// },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +1,67 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/home/view/agreement_and_privacy_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||||
import 'package:syncrow_web/pages/home/view/home_card.dart';
|
import 'package:syncrow_web/pages/home/view/home_card.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class HomeWebPage extends StatelessWidget {
|
class HomeWebPage extends StatefulWidget {
|
||||||
const HomeWebPage({super.key});
|
const HomeWebPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomeWebPage> createState() => _HomeWebPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeWebPageState extends State<HomeWebPage> {
|
||||||
|
// Flag to track whether the dialog is already shown.
|
||||||
|
bool _dialogShown = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||||
|
homeBloc.add(FetchUserInfo());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Size size = MediaQuery.of(context).size;
|
Size size = MediaQuery.of(context).size;
|
||||||
|
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||||
|
|
||||||
return PopScope(
|
return PopScope(
|
||||||
canPop: false,
|
canPop: false,
|
||||||
onPopInvoked: (didPop) => false,
|
onPopInvoked: (didPop) => false,
|
||||||
child: BlocConsumer<HomeBloc, HomeState>(
|
child: BlocConsumer<HomeBloc, HomeState>(
|
||||||
listener: (BuildContext context, state) {},
|
listener: (BuildContext context, state) {
|
||||||
|
if (state is HomeInitial) {
|
||||||
|
if (homeBloc.user!.hasAcceptedWebAgreement == false && !_dialogShown) {
|
||||||
|
_dialogShown = true; // Set the flag to true to indicate the dialog is showing.
|
||||||
|
Future.delayed(const Duration(seconds: 1), () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AgreementAndPrivacyDialog(
|
||||||
|
terms: homeBloc.terms,
|
||||||
|
policy: homeBloc.policy,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).then((v) {
|
||||||
|
_dialogShown = false;
|
||||||
|
if (v != null) {
|
||||||
|
homeBloc.add(ConfirmUserAgreementEvent());
|
||||||
|
homeBloc.add(const FetchUserInfo());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
|
||||||
return WebScaffold(
|
return WebScaffold(
|
||||||
enableMenuSidebar: false,
|
enableMenuSidebar: false,
|
||||||
appBarTitle: Row(
|
appBarTitle: Row(
|
||||||
@ -32,7 +75,10 @@ class HomeWebPage extends StatelessWidget {
|
|||||||
scaffoldBody: SizedBox(
|
scaffoldBody: SizedBox(
|
||||||
height: size.height,
|
height: size.height,
|
||||||
width: size.width,
|
width: size.width,
|
||||||
child: Column(
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -51,9 +97,9 @@ class HomeWebPage extends StatelessWidget {
|
|||||||
height: size.height * 0.6,
|
height: size.height * 0.6,
|
||||||
width: size.width * 0.68,
|
width: size.width * 0.68,
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
itemCount: 3, //8
|
itemCount: 3, // Change this count if needed.
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 4,
|
crossAxisCount: 3, // Adjust as needed.
|
||||||
crossAxisSpacing: 20.0,
|
crossAxisSpacing: 20.0,
|
||||||
mainAxisSpacing: 20.0,
|
mainAxisSpacing: 20.0,
|
||||||
childAspectRatio: 1.5,
|
childAspectRatio: 1.5,
|
||||||
@ -72,9 +118,12 @@ class HomeWebPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,185 +1,185 @@
|
|||||||
import 'package:flutter/material.dart';
|
// import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
// import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:graphview/GraphView.dart';
|
// import 'package:graphview/GraphView.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_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/home/bloc/home_event.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
// import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||||
|
|
||||||
class TreeWidget extends StatelessWidget {
|
// class TreeWidget extends StatelessWidget {
|
||||||
const TreeWidget({super.key});
|
// const TreeWidget({super.key});
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Widget build(BuildContext context) {
|
// Widget build(BuildContext context) {
|
||||||
// final HomeBloc homeBloc = BlocProvider.of<HomeBloc>(context);
|
// // final HomeBloc homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||||
String firstNodeName = '';
|
// String firstNodeName = '';
|
||||||
String secondNodeName = '';
|
// String secondNodeName = '';
|
||||||
|
|
||||||
return SafeArea(
|
// return SafeArea(
|
||||||
child: Container(
|
// child: Container(
|
||||||
padding: const EdgeInsets.all(24),
|
// padding: const EdgeInsets.all(24),
|
||||||
width: MediaQuery.sizeOf(context).width,
|
// width: MediaQuery.sizeOf(context).width,
|
||||||
height: MediaQuery.sizeOf(context).height,
|
// height: MediaQuery.sizeOf(context).height,
|
||||||
alignment: AlignmentDirectional.center,
|
// alignment: AlignmentDirectional.center,
|
||||||
child: Column(
|
// child: Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
// mainAxisSize: MainAxisSize.max,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
// children: [
|
||||||
BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
// BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
||||||
if (state is HomeInitial) {
|
// if (state is HomeInitial) {
|
||||||
return Wrap(
|
// return Wrap(
|
||||||
children: [
|
// children: [
|
||||||
SizedBox(
|
// SizedBox(
|
||||||
width: 100,
|
// width: 100,
|
||||||
child: TextFormField(
|
// child: TextFormField(
|
||||||
decoration: const InputDecoration(
|
// decoration: const InputDecoration(
|
||||||
labelText: "Subtree separation"),
|
// labelText: "Subtree separation"),
|
||||||
onChanged: (text) {
|
// onChanged: (text) {
|
||||||
firstNodeName = text;
|
// firstNodeName = text;
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const SizedBox(
|
// const SizedBox(
|
||||||
width: 8,
|
// width: 8,
|
||||||
),
|
// ),
|
||||||
Container(
|
// Container(
|
||||||
width: 100,
|
// width: 100,
|
||||||
child: TextFormField(
|
// child: TextFormField(
|
||||||
decoration: InputDecoration(labelText: "Node Name"),
|
// decoration: InputDecoration(labelText: "Node Name"),
|
||||||
onChanged: (text) {
|
// onChanged: (text) {
|
||||||
secondNodeName = text;
|
// secondNodeName = text;
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
ElevatedButton(
|
// ElevatedButton(
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
final node1 = Node.Id(firstNodeName);
|
// final node1 = Node.Id(firstNodeName);
|
||||||
final node2 = Node.Id(secondNodeName);
|
// final node2 = Node.Id(secondNodeName);
|
||||||
context.read<HomeBloc>().add(CreateNewNode(
|
// context.read<HomeBloc>().add(CreateNewNode(
|
||||||
sourceNode: node1, destinationNode: node2));
|
// sourceNode: node1, destinationNode: node2));
|
||||||
},
|
// },
|
||||||
child: Text("Add"),
|
// child: Text("Add"),
|
||||||
)
|
// )
|
||||||
],
|
// ],
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
if (state is HomeUpdateTree) {
|
// if (state is HomeUpdateTree) {
|
||||||
return Expanded(
|
// return Expanded(
|
||||||
child: InteractiveViewer(
|
// child: InteractiveViewer(
|
||||||
constrained: false,
|
// constrained: false,
|
||||||
boundaryMargin: const EdgeInsets.all(100),
|
// boundaryMargin: const EdgeInsets.all(100),
|
||||||
minScale: 0.01,
|
// minScale: 0.01,
|
||||||
maxScale: 5.6,
|
// maxScale: 5.6,
|
||||||
child: GraphView(
|
// child: GraphView(
|
||||||
graph: state.graph,
|
// graph: state.graph,
|
||||||
algorithm: BuchheimWalkerAlgorithm(
|
// algorithm: BuchheimWalkerAlgorithm(
|
||||||
state.builder, TreeEdgeRenderer(state.builder)),
|
// state.builder, TreeEdgeRenderer(state.builder)),
|
||||||
paint: Paint()
|
// paint: Paint()
|
||||||
..color = Colors.green
|
// ..color = Colors.green
|
||||||
..strokeWidth = 1
|
// ..strokeWidth = 1
|
||||||
..style = PaintingStyle.stroke,
|
// ..style = PaintingStyle.stroke,
|
||||||
builder: (Node node) {
|
// builder: (Node node) {
|
||||||
// I can decide what widget should be shown here based on the id
|
// // I can decide what widget should be shown here based on the id
|
||||||
var nodeName = node.key!.value;
|
// var nodeName = node.key!.value;
|
||||||
return rectangleWidget(nodeName, node, context);
|
// return rectangleWidget(nodeName, node, context);
|
||||||
},
|
// },
|
||||||
)),
|
// )),
|
||||||
);
|
// );
|
||||||
} else {
|
// } else {
|
||||||
return Container();
|
// return Container();
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
|
// Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
|
||||||
String nodeName = '';
|
// String nodeName = '';
|
||||||
return InkWell(
|
// return InkWell(
|
||||||
onTap: () {
|
// onTap: () {
|
||||||
showDialog(
|
// showDialog(
|
||||||
context: blocContext,
|
// context: blocContext,
|
||||||
builder: (BuildContext context) {
|
// builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
// return AlertDialog(
|
||||||
title: const Text('Add a child'),
|
// title: const Text('Add a child'),
|
||||||
content: TextField(
|
// content: TextField(
|
||||||
decoration:
|
// decoration:
|
||||||
const InputDecoration(hintText: 'Enter your text here'),
|
// const InputDecoration(hintText: 'Enter your text here'),
|
||||||
onChanged: (value) {
|
// onChanged: (value) {
|
||||||
nodeName = value;
|
// nodeName = value;
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
actions: <Widget>[
|
// actions: <Widget>[
|
||||||
TextButton(
|
// TextButton(
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
Navigator.of(context).pop();
|
// Navigator.of(context).pop();
|
||||||
},
|
// },
|
||||||
child: Text('Close'),
|
// child: Text('Close'),
|
||||||
),
|
// ),
|
||||||
TextButton(
|
// TextButton(
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
if (nodeName.isNotEmpty) {
|
// if (nodeName.isNotEmpty) {
|
||||||
final newNode = Node.Id(nodeName);
|
// final newNode = Node.Id(nodeName);
|
||||||
blocContext.read<HomeBloc>().add(CreateNewNode(
|
// blocContext.read<HomeBloc>().add(CreateNewNode(
|
||||||
sourceNode: node, destinationNode: newNode));
|
// sourceNode: node, destinationNode: newNode));
|
||||||
}
|
// }
|
||||||
Navigator.of(context).pop();
|
// Navigator.of(context).pop();
|
||||||
},
|
// },
|
||||||
child: Text('Add'),
|
// child: Text('Add'),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
child: Container(
|
// child: Container(
|
||||||
width: MediaQuery.of(blocContext).size.width * 0.2,
|
// width: MediaQuery.of(blocContext).size.width * 0.2,
|
||||||
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
// margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||||
padding: EdgeInsets.all(20.0),
|
// padding: EdgeInsets.all(20.0),
|
||||||
decoration: BoxDecoration(
|
// decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
// color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
// borderRadius: BorderRadius.circular(10.0),
|
||||||
boxShadow: [
|
// boxShadow: [
|
||||||
BoxShadow(
|
// BoxShadow(
|
||||||
color: Colors.grey.withOpacity(0.5),
|
// color: Colors.grey.withOpacity(0.5),
|
||||||
spreadRadius: 2,
|
// spreadRadius: 2,
|
||||||
blurRadius: 5,
|
// blurRadius: 5,
|
||||||
offset: Offset(0, 3), // changes position of shadow
|
// offset: Offset(0, 3), // changes position of shadow
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
child: Row(
|
// child: Row(
|
||||||
children: [
|
// children: [
|
||||||
const SizedBox(
|
// const SizedBox(
|
||||||
child: Icon(
|
// child: Icon(
|
||||||
Icons.location_on,
|
// Icons.location_on,
|
||||||
color: Colors.blue,
|
// color: Colors.blue,
|
||||||
size: 40.0,
|
// size: 40.0,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const SizedBox(width: 10.0),
|
// const SizedBox(width: 10.0),
|
||||||
SizedBox(
|
// SizedBox(
|
||||||
child: Text(
|
// child: Text(
|
||||||
text,
|
// text,
|
||||||
style: const TextStyle(
|
// style: const TextStyle(
|
||||||
fontSize: 24.0,
|
// fontSize: 24.0,
|
||||||
fontWeight: FontWeight.bold,
|
// fontWeight: FontWeight.bold,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const Spacer(),
|
// const Spacer(),
|
||||||
Container(
|
// Container(
|
||||||
child: const Icon(
|
// child: const Icon(
|
||||||
Icons.add_circle_outline,
|
// Icons.add_circle_outline,
|
||||||
color: Colors.grey,
|
// color: Colors.grey,
|
||||||
size: 24.0,
|
// size: 24.0,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|||||||
@ -42,7 +42,9 @@ class RolesUserModel {
|
|||||||
invitedBy:
|
invitedBy:
|
||||||
json['invitedBy'].toString().toLowerCase().replaceAll("_", " "),
|
json['invitedBy'].toString().toLowerCase().replaceAll("_", " "),
|
||||||
phoneNumber: json['phoneNumber'],
|
phoneNumber: json['phoneNumber'],
|
||||||
jobTitle: json['jobTitle'] ?? "-",
|
jobTitle: json['jobTitle'] == null || json['jobTitle'] == " "
|
||||||
|
? "_"
|
||||||
|
: json['jobTitle'],
|
||||||
createdDate: json['createdDate'],
|
createdDate: json['createdDate'],
|
||||||
createdTime: json['createdTime'],
|
createdTime: json['createdTime'],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/common/custom_dialog.dart';
|
import 'package:syncrow_web/pages/common/custom_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/model/edit_user_model.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/model/edit_user_model.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/model/role_type_model.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/model/role_type_model.dart';
|
||||||
@ -12,6 +13,9 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model
|
|||||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
import 'package:syncrow_web/services/user_permission.dart';
|
import 'package:syncrow_web/services/user_permission.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
|
|
||||||
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||||
UsersBloc() : super(UsersInitial()) {
|
UsersBloc() : super(UsersInitial()) {
|
||||||
@ -74,18 +78,24 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
|
|
||||||
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
||||||
String communityUuid) async {
|
String communityUuid) async {
|
||||||
return await CommunitySpaceManagementApi().getSpaceHierarchy(communityUuid);
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
return await CommunitySpaceManagementApi()
|
||||||
|
.getSpaceHierarchy(communityUuid, projectUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TreeNode> updatedCommunities = [];
|
List<TreeNode> updatedCommunities = [];
|
||||||
List<TreeNode> spacesNodes = [];
|
List<TreeNode> spacesNodes = [];
|
||||||
|
List<String> communityIds = [];
|
||||||
_onLoadCommunityAndSpaces(
|
_onLoadCommunityAndSpaces(
|
||||||
LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
|
LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
List<CommunityModel> communities =
|
List<CommunityModel> communities =
|
||||||
await CommunitySpaceManagementApi().fetchCommunities();
|
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
|
||||||
|
communityIds = communities.map((community) => community.uuid).toList();
|
||||||
updatedCommunities = await Future.wait(
|
updatedCommunities = await Future.wait(
|
||||||
communities.map((community) async {
|
communities.map((community) async {
|
||||||
List<SpaceModel> spaces =
|
List<SpaceModel> spaces =
|
||||||
@ -101,13 +111,19 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
);
|
);
|
||||||
|
originalCommunities = updatedCommunities;
|
||||||
emit(const SpacesLoadedState());
|
emit(const SpacesLoadedState());
|
||||||
return updatedCommunities;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This variable holds the full original list.
|
||||||
|
List<TreeNode> originalCommunities = [];
|
||||||
|
|
||||||
|
// This variable holds the working list that may be filtered.
|
||||||
|
|
||||||
|
// Build tree nodes from your data model.
|
||||||
List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
||||||
return spaces.map((space) {
|
return spaces.map((space) {
|
||||||
List<TreeNode> childNodes =
|
List<TreeNode> childNodes =
|
||||||
@ -123,12 +139,39 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optional helper method to deep clone a TreeNode.
|
||||||
|
TreeNode _cloneNode(TreeNode node) {
|
||||||
|
return TreeNode(
|
||||||
|
uuid: node.uuid,
|
||||||
|
title: node.title,
|
||||||
|
isChecked: node.isChecked,
|
||||||
|
isHighlighted: node.isHighlighted,
|
||||||
|
isExpanded: node.isExpanded,
|
||||||
|
children: node.children.map(_cloneNode).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone an entire list of tree nodes.
|
||||||
|
List<TreeNode> _cloneNodes(List<TreeNode> nodes) {
|
||||||
|
return nodes.map(_cloneNode).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Your search event handler.
|
||||||
void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
|
|
||||||
|
// If the search term is empty, restore the original list.
|
||||||
if (event.searchTerm!.isEmpty) {
|
if (event.searchTerm!.isEmpty) {
|
||||||
|
// Clear any highlights on the restored copy.
|
||||||
|
updatedCommunities = _cloneNodes(originalCommunities);
|
||||||
_clearHighlights(updatedCommunities);
|
_clearHighlights(updatedCommunities);
|
||||||
} else {
|
} else {
|
||||||
_searchAndHighlightNodes(updatedCommunities, event.searchTerm!);
|
// Start with a fresh clone of the original tree.
|
||||||
|
List<TreeNode> freshClone = _cloneNodes(originalCommunities);
|
||||||
|
|
||||||
|
_searchAndHighlightNodes(freshClone, event.searchTerm!);
|
||||||
|
|
||||||
|
updatedCommunities = _filterNodes(freshClone, event.searchTerm!);
|
||||||
}
|
}
|
||||||
emit(ChangeStatusSteps());
|
emit(ChangeStatusSteps());
|
||||||
}
|
}
|
||||||
@ -155,6 +198,91 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
return anyMatch;
|
return anyMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<TreeNode> _filterNodes(List<TreeNode> nodes, String searchTerm) {
|
||||||
|
List<TreeNode> filteredNodes = [];
|
||||||
|
for (var node in nodes) {
|
||||||
|
bool isMatch =
|
||||||
|
node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
List<TreeNode> filteredChildren = _filterNodes(node.children, searchTerm);
|
||||||
|
if (isMatch || filteredChildren.isNotEmpty) {
|
||||||
|
node.isHighlighted = isMatch;
|
||||||
|
node.children = filteredChildren;
|
||||||
|
filteredNodes.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
||||||
|
// return spaces.map((space) {
|
||||||
|
// List<TreeNode> childNodes =
|
||||||
|
// space.children.isNotEmpty ? _buildTreeNodes(space.children) : [];
|
||||||
|
// return TreeNode(
|
||||||
|
// uuid: space.uuid!,
|
||||||
|
// title: space.name,
|
||||||
|
// isChecked: false,
|
||||||
|
// isHighlighted: false,
|
||||||
|
// isExpanded: childNodes.isNotEmpty,
|
||||||
|
// children: childNodes,
|
||||||
|
// );
|
||||||
|
// }).toList();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
||||||
|
// emit(UsersLoadingState());
|
||||||
|
// if (event.searchTerm!.isEmpty) {
|
||||||
|
// _clearHighlights(updatedCommunities);
|
||||||
|
// } else {
|
||||||
|
// _searchAndHighlightNodes(updatedCommunities, event.searchTerm!);
|
||||||
|
// updatedCommunities = _filterNodes(updatedCommunities, event.searchTerm!);
|
||||||
|
// }
|
||||||
|
// emit(ChangeStatusSteps());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void _clearHighlights(List<TreeNode> nodes) {
|
||||||
|
// for (var node in nodes) {
|
||||||
|
// node.isHighlighted = false;
|
||||||
|
// if (node.children.isNotEmpty) {
|
||||||
|
// _clearHighlights(node.children);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bool _searchAndHighlightNodes(List<TreeNode> nodes, String searchTerm) {
|
||||||
|
// bool anyMatch = false;
|
||||||
|
// for (var node in nodes) {
|
||||||
|
// bool isMatch =
|
||||||
|
// node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
// bool childMatch = _searchAndHighlightNodes(node.children, searchTerm);
|
||||||
|
// node.isHighlighted = isMatch || childMatch;
|
||||||
|
|
||||||
|
// anyMatch = anyMatch || node.isHighlighted;
|
||||||
|
// }
|
||||||
|
// return anyMatch;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// List<TreeNode> _filterNodes(List<TreeNode> nodes, String searchTerm) {
|
||||||
|
// List<TreeNode> filteredNodes = [];
|
||||||
|
// for (var node in nodes) {
|
||||||
|
// // Check if the current node's title contains the search term.
|
||||||
|
// bool isMatch =
|
||||||
|
// node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
|
||||||
|
// // Recursively filter the children.
|
||||||
|
// List<TreeNode> filteredChildren = _filterNodes(node.children, searchTerm);
|
||||||
|
|
||||||
|
// // If the current node is a match or any of its children are, include it.
|
||||||
|
// if (isMatch || filteredChildren.isNotEmpty) {
|
||||||
|
// // Optionally, update any properties (like isHighlighted) if you still need them.
|
||||||
|
// node.isHighlighted = isMatch;
|
||||||
|
// // Replace the children with the filtered ones.
|
||||||
|
// node.children = filteredChildren;
|
||||||
|
// filteredNodes.add(node);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return filteredNodes;
|
||||||
|
// }
|
||||||
|
|
||||||
List<String> selectedIds = [];
|
List<String> selectedIds = [];
|
||||||
|
|
||||||
List<String> getSelectedIds(List<TreeNode> nodes) {
|
List<String> getSelectedIds(List<TreeNode> nodes) {
|
||||||
@ -177,7 +305,6 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
try {
|
try {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
roles = await UserPermissionApi().fetchRoles();
|
roles = await UserPermissionApi().fetchRoles();
|
||||||
// add(PermissionEvent(roleUuid: roles.first.uuid));
|
|
||||||
emit(RolePermissionInitial());
|
emit(RolePermissionInitial());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||||
@ -208,10 +335,15 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
return anyMatch;
|
return anyMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
void _sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||||
|
.where((id) => !communityIds.contains(id))
|
||||||
|
.toList();
|
||||||
|
|
||||||
bool res = await UserPermissionApi().sendInviteUser(
|
bool res = await UserPermissionApi().sendInviteUser(
|
||||||
email: emailController.text,
|
email: emailController.text,
|
||||||
firstName: firstNameController.text,
|
firstName: firstNameController.text,
|
||||||
@ -220,8 +352,9 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
phoneNumber: phoneController.text,
|
phoneNumber: phoneController.text,
|
||||||
roleUuid: roleSelected,
|
roleUuid: roleSelected,
|
||||||
spaceUuids: selectedIds,
|
spaceUuids: selectedIds,
|
||||||
);
|
projectUuid: projectUuid);
|
||||||
if (res == true) {
|
|
||||||
|
if (res) {
|
||||||
showCustomDialog(
|
showCustomDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
context: event.context,
|
context: event.context,
|
||||||
@ -251,7 +384,11 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
_editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
|
_editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||||
|
.where((id) => !communityIds.contains(id))
|
||||||
|
.toList();
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
bool res = await UserPermissionApi().editInviteUser(
|
bool res = await UserPermissionApi().editInviteUser(
|
||||||
userId: event.userId,
|
userId: event.userId,
|
||||||
firstName: firstNameController.text,
|
firstName: firstNameController.text,
|
||||||
@ -260,7 +397,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
phoneNumber: phoneController.text,
|
phoneNumber: phoneController.text,
|
||||||
roleUuid: roleSelected,
|
roleUuid: roleSelected,
|
||||||
spaceUuids: selectedIds,
|
spaceUuids: selectedIds,
|
||||||
);
|
projectUuid: projectUuid);
|
||||||
if (res == true) {
|
if (res == true) {
|
||||||
showCustomDialog(
|
showCustomDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
@ -365,8 +502,11 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
if (event.uuid?.isNotEmpty ?? false) {
|
if (event.uuid?.isNotEmpty ?? false) {
|
||||||
final res = await UserPermissionApi().fetchUserById(event.uuid);
|
final res =
|
||||||
|
await UserPermissionApi().fetchUserById(event.uuid, projectUuid);
|
||||||
|
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
// Populate the text controllers
|
// Populate the text controllers
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||||
@ -34,8 +35,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
return Dialog(
|
return Dialog(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
|
||||||
width: 900,
|
width: 900,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -64,8 +64,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
children: [
|
children: [
|
||||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||||
_buildStep3Indicator(
|
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
||||||
3, "Role & Permissions", _blocRole),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -113,15 +112,12 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
if (currentStep < 3) {
|
if (currentStep < 3) {
|
||||||
currentStep++;
|
currentStep++;
|
||||||
if (currentStep == 2) {
|
if (currentStep == 2) {
|
||||||
_blocRole.add(
|
_blocRole.add(const CheckStepStatus(isEditUser: false));
|
||||||
const CheckStepStatus(isEditUser: false));
|
|
||||||
} else if (currentStep == 3) {
|
} else if (currentStep == 3) {
|
||||||
_blocRole
|
_blocRole.add(const CheckSpacesStepStatus());
|
||||||
.add(const CheckSpacesStepStatus());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_blocRole
|
_blocRole.add(SendInviteUsers(context: context));
|
||||||
.add(SendInviteUsers(context: context));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -129,11 +125,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
currentStep < 3 ? "Next" : "Save",
|
currentStep < 3 ? "Next" : "Save",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: (_blocRole.isCompleteSpaces == false ||
|
color: (_blocRole.isCompleteSpaces == false ||
|
||||||
_blocRole.isCompleteBasics ==
|
_blocRole.isCompleteBasics == false ||
|
||||||
false ||
|
_blocRole.isCompleteRolePermissions == false) &&
|
||||||
_blocRole
|
|
||||||
.isCompleteRolePermissions ==
|
|
||||||
false) &&
|
|
||||||
currentStep == 3
|
currentStep == 3
|
||||||
? ColorsManager.grayColor
|
? ColorsManager.grayColor
|
||||||
: ColorsManager.secondaryColor),
|
: ColorsManager.secondaryColor),
|
||||||
@ -204,12 +197,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -236,12 +225,16 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
currentStep = step;
|
|
||||||
bloc.add(const CheckStepStatus(isEditUser: false));
|
bloc.add(const CheckStepStatus(isEditUser: false));
|
||||||
|
currentStep = step;
|
||||||
|
Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
|
bloc.add(const CheckStepStatus(isEditUser: false));
|
||||||
|
});
|
||||||
if (step3 == 3) {
|
if (step3 == 3) {
|
||||||
|
Future.delayed(const Duration(seconds: 1), () {
|
||||||
bloc.add(const CheckRoleStepStatus());
|
bloc.add(const CheckRoleStepStatus());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -268,12 +261,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -330,12 +319,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -46,8 +46,9 @@ class BasicsView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Flexible(
|
||||||
width: MediaQuery.of(context).size.width * 0.18,
|
child: SizedBox(
|
||||||
|
// width: MediaQuery.of(context).size.width * 0.18,
|
||||||
height: MediaQuery.of(context).size.width * 0.08,
|
height: MediaQuery.of(context).size.width * 0.08,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -75,8 +76,8 @@ class BasicsView extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
style:
|
style: const TextStyle(
|
||||||
const TextStyle(color: ColorsManager.blackColor),
|
color: ColorsManager.blackColor),
|
||||||
// onChanged: (value) {
|
// onChanged: (value) {
|
||||||
// Future.delayed(const Duration(milliseconds: 200),
|
// Future.delayed(const Duration(milliseconds: 200),
|
||||||
// () {
|
// () {
|
||||||
@ -103,9 +104,11 @@ class BasicsView extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
SizedBox(
|
Flexible(
|
||||||
width: MediaQuery.of(context).size.width * 0.18,
|
child: SizedBox(
|
||||||
|
// width: MediaQuery.of(context).size.width * 0.18,
|
||||||
height: MediaQuery.of(context).size.width * 0.08,
|
height: MediaQuery.of(context).size.width * 0.08,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -142,8 +145,7 @@ class BasicsView extends StatelessWidget {
|
|||||||
decoration:
|
decoration:
|
||||||
inputTextFormDeco(hintText: "Enter last name")
|
inputTextFormDeco(hintText: "Enter last name")
|
||||||
.copyWith(
|
.copyWith(
|
||||||
hintStyle: context
|
hintStyle: context.textTheme.bodyMedium
|
||||||
.textTheme.bodyMedium
|
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -159,6 +161,7 @@ class BasicsView extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
@ -218,7 +221,7 @@ class BasicsView extends StatelessWidget {
|
|||||||
if (_blocRole.checkEmailValid != "Valid email") {
|
if (_blocRole.checkEmailValid != "Valid email") {
|
||||||
return _blocRole.checkEmailValid;
|
return _blocRole.checkEmailValid;
|
||||||
}
|
}
|
||||||
return null;
|
// return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||||
|
|||||||
@ -81,7 +81,7 @@ Future<void> showPopUpFilterMenu({
|
|||||||
),
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const Text(
|
const Text(
|
||||||
"Filter by Status",
|
"Filter by ",
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_event.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_state.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_state.dart';
|
||||||
import 'package:syncrow_web/services/user_permission.dart';
|
import 'package:syncrow_web/services/user_permission.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
|
|
||||||
class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||||
UserTableBloc() : super(TableInitial()) {
|
UserTableBloc() : super(TableInitial()) {
|
||||||
@ -27,7 +30,16 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
int currentPage = 1;
|
int currentPage = 1;
|
||||||
List<RolesUserModel> users = [];
|
List<RolesUserModel> users = [];
|
||||||
List<RolesUserModel> initialUsers = [];
|
List<RolesUserModel> initialUsers = [];
|
||||||
|
|
||||||
|
List<RolesUserModel> totalUsersCount = [];
|
||||||
String currentSortOrder = '';
|
String currentSortOrder = '';
|
||||||
|
|
||||||
|
String currentSortJopTitle = '';
|
||||||
|
String currentSortRole = '';
|
||||||
|
String currentSortCreatedDate = '';
|
||||||
|
String currentSortStatus = '';
|
||||||
|
String currentSortCreatedBy = '';
|
||||||
|
|
||||||
String currentSortOrderDate = '';
|
String currentSortOrderDate = '';
|
||||||
List<String> roleTypes = [];
|
List<String> roleTypes = [];
|
||||||
List<String> jobTitle = [];
|
List<String> jobTitle = [];
|
||||||
@ -37,12 +49,12 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
Future<void> _getUsers(GetUsers event, Emitter<UserTableState> emit) async {
|
Future<void> _getUsers(GetUsers event, Emitter<UserTableState> emit) async {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
roleTypes.clear();
|
roleTypes.clear();
|
||||||
jobTitle.clear();
|
jobTitle.clear();
|
||||||
createdBy.clear();
|
createdBy.clear();
|
||||||
// deActivate.clear();
|
users = await UserPermissionApi().fetchUsers(projectUuid);
|
||||||
users = await UserPermissionApi().fetchUsers();
|
|
||||||
|
|
||||||
users.sort((a, b) {
|
users.sort((a, b) {
|
||||||
final dateA = _parseDateTime(a.createdDate);
|
final dateA = _parseDateTime(a.createdDate);
|
||||||
final dateB = _parseDateTime(b.createdDate);
|
final dateB = _parseDateTime(b.createdDate);
|
||||||
@ -57,15 +69,13 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
for (var user in users) {
|
for (var user in users) {
|
||||||
createdBy.add(user.invitedBy.toString());
|
createdBy.add(user.invitedBy.toString());
|
||||||
}
|
}
|
||||||
// for (var user in users) {
|
|
||||||
// deActivate.add(user.status.toString());
|
|
||||||
// }
|
|
||||||
initialUsers = List.from(users);
|
initialUsers = List.from(users);
|
||||||
roleTypes = roleTypes.toSet().toList();
|
roleTypes = roleTypes.toSet().toList();
|
||||||
jobTitle = jobTitle.toSet().toList();
|
jobTitle = jobTitle.toSet().toList();
|
||||||
createdBy = createdBy.toSet().toList();
|
createdBy = createdBy.toSet().toList();
|
||||||
// deActivate = deActivate.toSet().toList();
|
|
||||||
_handlePageChange(ChangePage(1), emit);
|
_handlePageChange(ChangePage(1), emit);
|
||||||
|
totalUsersCount = initialUsers;
|
||||||
|
add(ChangePage(currentPage));
|
||||||
emit(UsersLoadedState(users: users));
|
emit(UsersLoadedState(users: users));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ErrorState(e.toString()));
|
emit(ErrorState(e.toString()));
|
||||||
@ -91,31 +101,13 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
Future<void> _changeUserStatus(
|
Future<void> _changeUserStatus(
|
||||||
ChangeUserStatus event, Emitter<UserTableState> emit) async {
|
ChangeUserStatus event, Emitter<UserTableState> emit) async {
|
||||||
try {
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
bool res = await UserPermissionApi().changeUserStatusById(
|
bool res = await UserPermissionApi().changeUserStatusById(event.userId,
|
||||||
event.userId, event.newStatus == "disabled" ? false : true);
|
event.newStatus == "disabled" ? false : true, projectUuid);
|
||||||
if (res == true) {
|
if (res == true) {
|
||||||
add(const GetUsers());
|
add(const GetUsers());
|
||||||
// users = users.map((user) {
|
|
||||||
// if (user.uuid == event.userId) {
|
|
||||||
// return RolesUserModel(
|
|
||||||
// uuid: user.uuid,
|
|
||||||
// createdAt: user.createdAt,
|
|
||||||
// email: user.email,
|
|
||||||
// firstName: user.firstName,
|
|
||||||
// lastName: user.lastName,
|
|
||||||
// roleType: user.roleType,
|
|
||||||
// status: event.newStatus,
|
|
||||||
// isEnabled: event.newStatus == "disabled" ? false : true,
|
|
||||||
// invitedBy: user.invitedBy,
|
|
||||||
// phoneNumber: user.phoneNumber,
|
|
||||||
// jobTitle: user.jobTitle,
|
|
||||||
// createdDate: user.createdDate,
|
|
||||||
// createdTime: user.createdTime,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// return user;
|
|
||||||
// }).toList();
|
|
||||||
}
|
}
|
||||||
emit(UsersLoadedState(users: users));
|
emit(UsersLoadedState(users: users));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -125,11 +117,14 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
|
|
||||||
void _toggleSortUsersByNameAsc(
|
void _toggleSortUsersByNameAsc(
|
||||||
SortUsersByNameAsc event, Emitter<UserTableState> emit) {
|
SortUsersByNameAsc event, Emitter<UserTableState> emit) {
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedJobTitles.clear();
|
||||||
|
selectedCreatedBy.clear();
|
||||||
|
selectedStatuses.clear();
|
||||||
if (currentSortOrder == "Asc") {
|
if (currentSortOrder == "Asc") {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
users = List.from(users);
|
users = List.from(users);
|
||||||
emit(UsersLoadedState(users: users));
|
|
||||||
} else {
|
} else {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "Asc";
|
currentSortOrder = "Asc";
|
||||||
@ -137,28 +132,42 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
.toString()
|
.toString()
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.compareTo(b.firstName.toString().toLowerCase()));
|
.compareTo(b.firstName.toString().toLowerCase()));
|
||||||
emit(UsersLoadedState(users: users));
|
|
||||||
}
|
}
|
||||||
|
currentSortJopTitle = '';
|
||||||
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
emit(UsersLoadedState(users: users));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _toggleSortUsersByNameDesc(
|
void _toggleSortUsersByNameDesc(
|
||||||
SortUsersByNameDesc event, Emitter<UserTableState> emit) {
|
SortUsersByNameDesc event, Emitter<UserTableState> emit) {
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedJobTitles.clear();
|
||||||
|
selectedCreatedBy.clear();
|
||||||
|
selectedStatuses.clear();
|
||||||
if (currentSortOrder == "Desc") {
|
if (currentSortOrder == "Desc") {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
users = List.from(initialUsers); // Reset to saved initial state
|
users = List.from(initialUsers);
|
||||||
emit(UsersLoadedState(users: users));
|
|
||||||
} else {
|
} else {
|
||||||
// Sort descending
|
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
users.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
users.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
emit(UsersLoadedState(users: users));
|
|
||||||
}
|
}
|
||||||
|
currentSortJopTitle = '';
|
||||||
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
emit(UsersLoadedState(users: users));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _toggleSortUsersByDateNewestToOldest(
|
void _toggleSortUsersByDateNewestToOldest(
|
||||||
DateNewestToOldestEvent event, Emitter<UserTableState> emit) {
|
DateNewestToOldestEvent event, Emitter<UserTableState> emit) {
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedJobTitles.clear();
|
||||||
|
selectedCreatedBy.clear();
|
||||||
|
selectedStatuses.clear();
|
||||||
if (currentSortOrderDate == "NewestToOldest") {
|
if (currentSortOrderDate == "NewestToOldest") {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
@ -179,6 +188,10 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
|
|
||||||
void _toggleSortUsersByDateOldestToNewest(
|
void _toggleSortUsersByDateOldestToNewest(
|
||||||
DateOldestToNewestEvent event, Emitter<UserTableState> emit) {
|
DateOldestToNewestEvent event, Emitter<UserTableState> emit) {
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedJobTitles.clear();
|
||||||
|
selectedCreatedBy.clear();
|
||||||
|
selectedStatuses.clear();
|
||||||
if (currentSortOrderDate == "OldestToNewest") {
|
if (currentSortOrderDate == "OldestToNewest") {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
@ -212,6 +225,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
Future<void> _searchUsers(
|
Future<void> _searchUsers(
|
||||||
SearchUsers event, Emitter<UserTableState> emit) async {
|
SearchUsers event, Emitter<UserTableState> emit) async {
|
||||||
try {
|
try {
|
||||||
|
emit(TableSearch());
|
||||||
final query = event.query.toLowerCase();
|
final query = event.query.toLowerCase();
|
||||||
final filteredUsers = initialUsers.where((user) {
|
final filteredUsers = initialUsers.where((user) {
|
||||||
final fullName = "${user.firstName} ${user.lastName}".toLowerCase();
|
final fullName = "${user.firstName} ${user.lastName}".toLowerCase();
|
||||||
@ -240,7 +254,8 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handlePageChange(ChangePage event, Emitter<UserTableState> emit) {
|
void _handlePageChange(ChangePage event, Emitter<UserTableState> emit) {
|
||||||
const itemsPerPage = 10;
|
currentPage = event.pageNumber;
|
||||||
|
const itemsPerPage = 20;
|
||||||
final startIndex = (event.pageNumber - 1) * itemsPerPage;
|
final startIndex = (event.pageNumber - 1) * itemsPerPage;
|
||||||
final endIndex = startIndex + itemsPerPage;
|
final endIndex = startIndex + itemsPerPage;
|
||||||
if (startIndex >= users.length) {
|
if (startIndex >= users.length) {
|
||||||
@ -277,9 +292,15 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
} else if (event.sortOrder == "Desc") {
|
} else if (event.sortOrder == "Desc") {
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
} else {
|
} else {}
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
}
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
currentSortJopTitle = '';
|
||||||
|
currentSortOrderDate = "";
|
||||||
|
|
||||||
|
totalUsersCount = filteredUsers;
|
||||||
|
|
||||||
emit(UsersLoadedState(users: filteredUsers));
|
emit(UsersLoadedState(users: filteredUsers));
|
||||||
}
|
}
|
||||||
@ -301,9 +322,16 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
} else if (event.sortOrder == "Desc") {
|
} else if (event.sortOrder == "Desc") {
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
} else {
|
} else {}
|
||||||
currentSortOrder = "";
|
currentSortOrder = "";
|
||||||
}
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
currentSortRole = '';
|
||||||
|
currentSortOrderDate = "";
|
||||||
|
|
||||||
|
totalUsersCount = filteredUsers;
|
||||||
|
|
||||||
emit(UsersLoadedState(users: filteredUsers));
|
emit(UsersLoadedState(users: filteredUsers));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,9 +353,15 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
} else if (event.sortOrder == "Desc") {
|
} else if (event.sortOrder == "Desc") {
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
} else {
|
} else {}
|
||||||
currentSortOrder = "";
|
currentSortOrder = '';
|
||||||
}
|
currentSortRole = '';
|
||||||
|
currentSortCreatedDate = '';
|
||||||
|
currentSortStatus = '';
|
||||||
|
currentSortOrderDate = "";
|
||||||
|
|
||||||
|
totalUsersCount = filteredUsers;
|
||||||
|
|
||||||
emit(UsersLoadedState(users: filteredUsers));
|
emit(UsersLoadedState(users: filteredUsers));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +371,20 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
|
|
||||||
final filteredUsers = initialUsers.where((user) {
|
final filteredUsers = initialUsers.where((user) {
|
||||||
if (selectedStatuses.isEmpty) return true;
|
if (selectedStatuses.isEmpty) return true;
|
||||||
return selectedStatuses.contains(user.status);
|
|
||||||
|
return selectedStatuses.any((status) {
|
||||||
|
final userStatus = user.status?.toLowerCase() ?? '';
|
||||||
|
switch (status.toLowerCase()) {
|
||||||
|
case 'active':
|
||||||
|
return user.isEnabled == true && userStatus != 'invited';
|
||||||
|
case 'disabled':
|
||||||
|
return user.isEnabled == false;
|
||||||
|
case 'invited':
|
||||||
|
return userStatus == 'invited';
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}).toList();
|
}).toList();
|
||||||
if (event.sortOrder == "Asc") {
|
if (event.sortOrder == "Asc") {
|
||||||
currentSortOrder = "Asc";
|
currentSortOrder = "Asc";
|
||||||
@ -348,9 +395,14 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
|||||||
} else if (event.sortOrder == "Desc") {
|
} else if (event.sortOrder == "Desc") {
|
||||||
currentSortOrder = "Desc";
|
currentSortOrder = "Desc";
|
||||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||||
} else {
|
totalUsersCount = filteredUsers;
|
||||||
currentSortOrder = "";
|
} else {}
|
||||||
}
|
currentSortOrder = '';
|
||||||
|
currentSortRole = '';
|
||||||
|
currentSortCreatedDate = '';
|
||||||
|
currentSortCreatedBy = '';
|
||||||
|
currentSortOrderDate = "";
|
||||||
|
|
||||||
emit(UsersLoadedState(users: filteredUsers));
|
emit(UsersLoadedState(users: filteredUsers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,10 @@ final class TableInitial extends UserTableState {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
final class TableSearch extends UserTableState {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
final class RolesLoadingState extends UserTableState {
|
final class RolesLoadingState extends UserTableState {
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
|
|||||||
@ -12,7 +12,7 @@ Future<void> showDateFilterMenu({
|
|||||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
final RelativeRect position = RelativeRect.fromRect(
|
final RelativeRect position = RelativeRect.fromRect(
|
||||||
Rect.fromLTRB(
|
Rect.fromLTRB(
|
||||||
overlay.size.width / 2,
|
overlay.size.width / 3,
|
||||||
240,
|
240,
|
||||||
0,
|
0,
|
||||||
overlay.size.height,
|
overlay.size.height,
|
||||||
@ -40,7 +40,6 @@ Future<void> showDateFilterMenu({
|
|||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
"Sort from newest to oldest",
|
"Sort from newest to oldest",
|
||||||
// style: context.textTheme.bodyMedium,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isSelected == "NewestToOldest"
|
color: isSelected == "NewestToOldest"
|
||||||
? Colors.black
|
? Colors.black
|
||||||
@ -65,9 +64,5 @@ Future<void> showDateFilterMenu({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).then((value) {
|
).then((value) {});
|
||||||
// setState(() {
|
|
||||||
// _isDropdownOpen = false;
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,7 +40,6 @@ Future<void> showDeActivateFilterMenu({
|
|||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
"Sort A to Z",
|
"Sort A to Z",
|
||||||
// style: context.textTheme.bodyMedium,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isSelected == "NewestToOldest"
|
color: isSelected == "NewestToOldest"
|
||||||
? Colors.black
|
? Colors.black
|
||||||
@ -65,9 +64,5 @@ Future<void> showDeActivateFilterMenu({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).then((value) {
|
).then((value) {});
|
||||||
// setState(() {
|
|
||||||
// _isDropdownOpen = false;
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ Future<void> showNameMenu({
|
|||||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||||
final RelativeRect position = RelativeRect.fromRect(
|
final RelativeRect position = RelativeRect.fromRect(
|
||||||
Rect.fromLTRB(
|
Rect.fromLTRB(
|
||||||
overlay.size.width / 25,
|
overlay.size.width / 35,
|
||||||
240,
|
240,
|
||||||
0,
|
0,
|
||||||
overlay.size.height,
|
overlay.size.height,
|
||||||
@ -40,7 +40,6 @@ Future<void> showNameMenu({
|
|||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
"Sort A to Z",
|
"Sort A to Z",
|
||||||
// style: context.textTheme.bodyMedium,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isSelected == "Asc" ? Colors.black : Colors.blueGrey),
|
color: isSelected == "Asc" ? Colors.black : Colors.blueGrey),
|
||||||
),
|
),
|
||||||
@ -61,9 +60,5 @@ Future<void> showNameMenu({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).then((value) {
|
).then((value) {});
|
||||||
// setState(() {
|
|
||||||
// _isDropdownOpen = false;
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,260 +1,264 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class DynamicTableScreen extends StatefulWidget {
|
class _HeaderColumn extends StatelessWidget {
|
||||||
final List<String> titles;
|
final String title;
|
||||||
final List<List<Widget>> rows;
|
final double width;
|
||||||
final void Function(int columnIndex)? onFilter;
|
final bool showFilter;
|
||||||
|
final VoidCallback? onFilter;
|
||||||
|
final Function(double) onResize;
|
||||||
|
|
||||||
DynamicTableScreen(
|
const _HeaderColumn({
|
||||||
{required this.titles, required this.rows, required this.onFilter});
|
required this.title,
|
||||||
|
required this.width,
|
||||||
@override
|
required this.showFilter,
|
||||||
_DynamicTableScreenState createState() => _DynamicTableScreenState();
|
required this.onResize,
|
||||||
}
|
this.onFilter,
|
||||||
|
Key? key,
|
||||||
class _DynamicTableScreenState extends State<DynamicTableScreen>
|
}) : super(key: key);
|
||||||
with WidgetsBindingObserver {
|
|
||||||
late List<double> columnWidths;
|
|
||||||
late double totalWidth;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
columnWidths = List<double>.filled(widget.titles.length, 150.0);
|
|
||||||
totalWidth = columnWidths.reduce((a, b) => a + b);
|
|
||||||
WidgetsBinding.instance.addObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeMetrics() {
|
|
||||||
super.didChangeMetrics();
|
|
||||||
final newScreenWidth = MediaQuery.of(context).size.width;
|
|
||||||
setState(() {
|
|
||||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
|
||||||
if (index == 1) {
|
|
||||||
return newScreenWidth *
|
|
||||||
0.12; // 20% of screen width for the second column
|
|
||||||
} else if (index == 9) {
|
|
||||||
return newScreenWidth *
|
|
||||||
0.1; // 25% of screen width for the tenth column
|
|
||||||
}
|
|
||||||
return newScreenWidth *
|
|
||||||
0.09; // Default to 10% of screen width for other columns
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
return MouseRegion(
|
||||||
if (columnWidths.every((width) => width == screenWidth * 7)) {
|
cursor: SystemMouseCursors.resizeColumn,
|
||||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
child: GestureDetector(
|
||||||
if (index == 1) {
|
onHorizontalDragUpdate: (details) => onResize(details.delta.dx),
|
||||||
return screenWidth * 0.11;
|
|
||||||
} else if (index == 9) {
|
|
||||||
return screenWidth * 0.1;
|
|
||||||
}
|
|
||||||
return screenWidth * 0.09;
|
|
||||||
});
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
return SingleChildScrollView(
|
|
||||||
clipBehavior: Clip.none,
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: containerDecoration.copyWith(
|
width: width,
|
||||||
color: ColorsManager.whiteColors,
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(20))),
|
decoration: const BoxDecoration(
|
||||||
child: FittedBox(
|
border: Border(right: BorderSide(color: ColorsManager.boxDivider)),
|
||||||
child: Column(
|
),
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: totalWidth,
|
|
||||||
decoration: containerDecoration.copyWith(
|
|
||||||
color: ColorsManager.circleRolesBackground,
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(15),
|
|
||||||
topRight: Radius.circular(15))),
|
|
||||||
child: Row(
|
|
||||||
children: List.generate(widget.titles.length, (index) {
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
FittedBox(
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.only(left: 5, right: 5),
|
|
||||||
width: columnWidths[index],
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.titles[index],
|
title,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
style: const TextStyle(
|
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: ColorsManager.grayColor,
|
color: ColorsManager.grayColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (index != 1 &&
|
if (showFilter)
|
||||||
index != 9 &&
|
IconButton(
|
||||||
index != 8 &&
|
icon: SvgPicture.asset(Assets.filterTableIcon),
|
||||||
index != 5)
|
onPressed: onFilter,
|
||||||
FittedBox(
|
padding: EdgeInsets.zero,
|
||||||
child: IconButton(
|
constraints: const BoxConstraints(),
|
||||||
icon: SvgPicture.asset(
|
|
||||||
Assets.filterTableIcon,
|
|
||||||
fit: BoxFit.none,
|
|
||||||
),
|
),
|
||||||
onPressed: () {
|
|
||||||
if (widget.onFilter != null) {
|
|
||||||
widget.onFilter!(index);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
GestureDetector(
|
);
|
||||||
onHorizontalDragUpdate: (details) {
|
}
|
||||||
setState(() {
|
}
|
||||||
columnWidths[index] =
|
|
||||||
(columnWidths[index] + details.delta.dx)
|
class _TableRow extends StatelessWidget {
|
||||||
.clamp(150.0, 300.0);
|
final List<Widget> cells;
|
||||||
totalWidth = columnWidths.reduce((a, b) => a + b);
|
final List<double> columnWidths;
|
||||||
});
|
final bool isLast;
|
||||||
},
|
|
||||||
child: MouseRegion(
|
const _TableRow({
|
||||||
cursor: SystemMouseCursors.resizeColumn,
|
required this.cells,
|
||||||
child: Container(
|
required this.columnWidths,
|
||||||
color: Colors.green,
|
required this.isLast,
|
||||||
child: Container(
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
for (int i = 0; i < cells.length; i++)
|
||||||
|
Container(
|
||||||
|
width: columnWidths[i],
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// border: Border(
|
||||||
|
// right: BorderSide(color: ColorsManager.boxDivider),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
child: cells[i],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (!isLast)
|
||||||
|
Divider(
|
||||||
|
height: 1,
|
||||||
|
thickness: 1,
|
||||||
color: ColorsManager.boxDivider,
|
color: ColorsManager.boxDivider,
|
||||||
width: 1,
|
|
||||||
height: 50,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}
|
||||||
|
}
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
class DynamicTableScreen extends StatefulWidget {
|
||||||
|
final List<String> titles;
|
||||||
|
final List<List<Widget>> rows;
|
||||||
|
final void Function(int columnIndex)? onFilter;
|
||||||
|
|
||||||
|
const DynamicTableScreen({
|
||||||
|
required this.titles,
|
||||||
|
required this.rows,
|
||||||
|
required this.onFilter,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DynamicTableScreenState createState() => _DynamicTableScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DynamicTableScreenState extends State<DynamicTableScreen> {
|
||||||
|
late List<double> columnWidths;
|
||||||
|
final double _minColumnWidth = 100.0;
|
||||||
|
final double _maxColumnWidth = 300.0;
|
||||||
|
final double _dividerWidth = 1.0;
|
||||||
|
double _lastAvailableWidth = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
columnWidths = List.filled(widget.titles.length, _minColumnWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleColumnResize(int index, double delta) {
|
||||||
|
setState(() {
|
||||||
|
double newWidth = columnWidths[index] + delta;
|
||||||
|
newWidth = newWidth.clamp(_minColumnWidth, _maxColumnWidth);
|
||||||
|
double actualDelta = newWidth - columnWidths[index];
|
||||||
|
if (actualDelta == 0) return;
|
||||||
|
|
||||||
|
int nextIndex = (index + 1) % columnWidths.length;
|
||||||
|
columnWidths[index] = newWidth;
|
||||||
|
columnWidths[nextIndex] = (columnWidths[nextIndex] - actualDelta)
|
||||||
|
.clamp(_minColumnWidth, _maxColumnWidth);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHeader() {
|
||||||
|
return Container(
|
||||||
|
decoration: containerDecoration.copyWith(
|
||||||
|
color: ColorsManager.circleRolesBackground,
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(15),
|
||||||
|
topRight: Radius.circular(15),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
widget.rows.isEmpty
|
child: Row(
|
||||||
? SizedBox(
|
|
||||||
height: MediaQuery.of(context).size.height / 2,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
Column(
|
for (int i = 0; i < widget.titles.length; i++)
|
||||||
|
_HeaderColumn(
|
||||||
|
title: widget.titles[i],
|
||||||
|
width: columnWidths[i],
|
||||||
|
showFilter: i != 1 && i != 9 && i != 8 && i != 5,
|
||||||
|
onFilter: () => widget.onFilter?.call(i),
|
||||||
|
onResize: (delta) => _handleColumnResize(i, delta),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBody() {
|
||||||
|
if (widget.rows.isEmpty) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 300,
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
SvgPicture.asset(Assets.emptyTable),
|
SvgPicture.asset(Assets.emptyTable),
|
||||||
const SizedBox(
|
const SizedBox(height: 15),
|
||||||
height: 15,
|
|
||||||
),
|
|
||||||
const Text(
|
const Text(
|
||||||
'No Users',
|
'No Users',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: ColorsManager.lightGrayColor,
|
color: ColorsManager.lightGrayColor,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w700),
|
fontWeight: FontWeight.w700,
|
||||||
)
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
: Center(
|
);
|
||||||
child: Container(
|
}
|
||||||
width: totalWidth,
|
|
||||||
|
return Container(
|
||||||
decoration: containerDecoration.copyWith(
|
decoration: containerDecoration.copyWith(
|
||||||
color: ColorsManager.whiteColors,
|
color: ColorsManager.whiteColors,
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
bottomLeft: Radius.circular(15),
|
bottomLeft: Radius.circular(15),
|
||||||
bottomRight: Radius.circular(15))),
|
bottomRight: Radius.circular(15),
|
||||||
child: ListView.builder(
|
),
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
),
|
||||||
shrinkWrap: true,
|
child: Column(
|
||||||
itemCount: widget.rows.length,
|
|
||||||
itemBuilder: (context, rowIndex) {
|
|
||||||
if (columnWidths.every((width) => width == 120.0)) {
|
|
||||||
columnWidths = List<double>.generate(
|
|
||||||
widget.titles.length, (index) {
|
|
||||||
if (index == 1) {
|
|
||||||
return screenWidth * 0.11;
|
|
||||||
} else if (index == 9) {
|
|
||||||
return screenWidth * 0.2;
|
|
||||||
}
|
|
||||||
return screenWidth * 0.11;
|
|
||||||
});
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
final row = widget.rows[rowIndex];
|
|
||||||
return Column(
|
|
||||||
children: [
|
children: [
|
||||||
Container(
|
for (int rowIndex = 0; rowIndex < widget.rows.length; rowIndex++)
|
||||||
child: Padding(
|
_TableRow(
|
||||||
padding: const EdgeInsets.only(
|
cells: widget.rows[rowIndex],
|
||||||
left: 5, top: 10, right: 5, bottom: 10),
|
columnWidths: columnWidths,
|
||||||
child: Row(
|
isLast: rowIndex == widget.rows.length - 1,
|
||||||
children:
|
|
||||||
List.generate(row.length, (index) {
|
|
||||||
return SizedBox(
|
|
||||||
width: columnWidths[index],
|
|
||||||
child: SizedBox(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 15, right: 10),
|
|
||||||
child: row[index],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (rowIndex < widget.rows.length - 1)
|
|
||||||
Row(
|
|
||||||
children: List.generate(
|
|
||||||
widget.titles.length, (index) {
|
|
||||||
return SizedBox(
|
|
||||||
width: columnWidths[index],
|
|
||||||
child: const Divider(
|
|
||||||
color: ColorsManager.boxDivider,
|
|
||||||
thickness: 1,
|
|
||||||
height: 1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final availableWidth = constraints.maxWidth;
|
||||||
|
final totalDividersWidth = (widget.titles.length - 1) * _dividerWidth;
|
||||||
|
|
||||||
|
if (_lastAvailableWidth != availableWidth) {
|
||||||
|
final equalWidth =
|
||||||
|
(availableWidth - totalDividersWidth) / widget.titles.length;
|
||||||
|
final clampedWidth =
|
||||||
|
equalWidth.clamp(_minColumnWidth, _maxColumnWidth);
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
setState(() {
|
||||||
|
columnWidths = List.filled(widget.titles.length, clampedWidth);
|
||||||
|
_lastAvailableWidth = availableWidth;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final totalTableWidth =
|
||||||
|
columnWidths.fold(0.0, (sum, w) => sum + w) + totalDividersWidth;
|
||||||
|
return SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Container(
|
||||||
|
width: totalTableWidth,
|
||||||
|
decoration: containerDecoration.copyWith(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildHeader(),
|
||||||
|
_buildBody(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,8 @@ class UsersPage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final TextEditingController searchController = TextEditingController();
|
final TextEditingController searchController = TextEditingController();
|
||||||
|
|
||||||
Widget actionButton({required String title, required Function()? onTap}) {
|
Widget actionButton(
|
||||||
|
{bool isActive = false, required String title, Function()? onTap}) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -33,7 +34,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: title == "Delete"
|
color: isActive == false && title != "Delete"
|
||||||
|
? Colors.grey
|
||||||
|
: title == "Delete"
|
||||||
? ColorsManager.red
|
? ColorsManager.red
|
||||||
: ColorsManager.spaceColor,
|
: ColorsManager.spaceColor,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -108,7 +111,6 @@ class UsersPage extends StatelessWidget {
|
|||||||
final screenSize = MediaQuery.of(context).size;
|
final screenSize = MediaQuery.of(context).size;
|
||||||
final _blocRole = BlocProvider.of<UserTableBloc>(context);
|
final _blocRole = BlocProvider.of<UserTableBloc>(context);
|
||||||
if (state is UsersLoadingState) {
|
if (state is UsersLoadingState) {
|
||||||
_blocRole.add(ChangePage(_blocRole.currentPage));
|
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (state is UsersLoadedState) {
|
} else if (state is UsersLoadedState) {
|
||||||
return Padding(
|
return Padding(
|
||||||
@ -130,9 +132,12 @@ class UsersPage extends StatelessWidget {
|
|||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: searchController,
|
controller: searchController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context
|
final bloc = context.read<UserTableBloc>();
|
||||||
.read<UserTableBloc>()
|
bloc.add(FilterClearEvent());
|
||||||
.add(SearchUsers(value));
|
bloc.add(SearchUsers(value));
|
||||||
|
if (value == '') {
|
||||||
|
bloc.add(ChangePage(1));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
style: const TextStyle(color: Colors.black),
|
style: const TextStyle(color: Colors.black),
|
||||||
decoration: textBoxDecoration(radios: 15)!.copyWith(
|
decoration: textBoxDecoration(radios: 15)!.copyWith(
|
||||||
@ -215,7 +220,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
|
|
||||||
showPopUpFilterMenu(
|
showPopUpFilterMenu(
|
||||||
position: RelativeRect.fromLTRB(
|
position: RelativeRect.fromLTRB(
|
||||||
overlay.size.width / 4,
|
overlay.size.width / 5.3,
|
||||||
240,
|
240,
|
||||||
overlay.size.width / 4,
|
overlay.size.width / 4,
|
||||||
0,
|
0,
|
||||||
@ -223,8 +228,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
list: _blocRole.jobTitle,
|
list: _blocRole.jobTitle,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortJopTitle,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
@ -233,14 +239,14 @@ class UsersPage extends StatelessWidget {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
_blocRole.add(FilterUsersByJobEvent(
|
_blocRole.add(FilterUsersByJobEvent(
|
||||||
selectedJob: selectedItems,
|
selectedJob: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortOrder,
|
sortOrder: _blocRole.currentSortJopTitle,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortJopTitle = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortJopTitle = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -263,8 +269,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
list: _blocRole.roleTypes,
|
list: _blocRole.roleTypes,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortRole,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
@ -274,13 +281,13 @@ class UsersPage extends StatelessWidget {
|
|||||||
context.read<UserTableBloc>().add(
|
context.read<UserTableBloc>().add(
|
||||||
FilterUsersByRoleEvent(
|
FilterUsersByRoleEvent(
|
||||||
selectedRoles: selectedItems,
|
selectedRoles: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortOrder));
|
sortOrder: _blocRole.currentSortRole));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortRole = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortRole = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -318,8 +325,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
list: _blocRole.createdBy,
|
list: _blocRole.createdBy,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortCreatedBy,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
@ -328,13 +336,13 @@ class UsersPage extends StatelessWidget {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
_blocRole.add(FilterUsersByCreatedEvent(
|
_blocRole.add(FilterUsersByCreatedEvent(
|
||||||
selectedCreatedBy: selectedItems,
|
selectedCreatedBy: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortOrder));
|
sortOrder: _blocRole.currentSortCreatedBy));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortCreatedBy = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortCreatedBy = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -343,6 +351,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
for (var item in _blocRole.status)
|
for (var item in _blocRole.status)
|
||||||
item: _blocRole.selectedStatuses.contains(item),
|
item: _blocRole.selectedStatuses.contains(item),
|
||||||
};
|
};
|
||||||
|
|
||||||
final RenderBox overlay = Overlay.of(context)
|
final RenderBox overlay = Overlay.of(context)
|
||||||
.context
|
.context
|
||||||
.findRenderObject() as RenderBox;
|
.findRenderObject() as RenderBox;
|
||||||
@ -350,16 +359,16 @@ class UsersPage extends StatelessWidget {
|
|||||||
position: RelativeRect.fromLTRB(
|
position: RelativeRect.fromLTRB(
|
||||||
overlay.size.width / 0,
|
overlay.size.width / 0,
|
||||||
240,
|
240,
|
||||||
overlay.size.width / 4,
|
overlay.size.width / 5,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
list: _blocRole.status,
|
list: _blocRole.status,
|
||||||
context: context,
|
context: context,
|
||||||
checkboxStates: checkboxStates,
|
checkboxStates: checkboxStates,
|
||||||
isSelected: _blocRole.currentSortOrder,
|
isSelected: _blocRole.currentSortStatus,
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
|
searchController.clear();
|
||||||
_blocRole.add(FilterClearEvent());
|
_blocRole.add(FilterClearEvent());
|
||||||
|
|
||||||
final selectedItems = checkboxStates.entries
|
final selectedItems = checkboxStates.entries
|
||||||
.where((entry) => entry.value)
|
.where((entry) => entry.value)
|
||||||
.map((entry) => entry.key)
|
.map((entry) => entry.key)
|
||||||
@ -367,13 +376,13 @@ class UsersPage extends StatelessWidget {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
_blocRole.add(FilterUsersByDeActevateEvent(
|
_blocRole.add(FilterUsersByDeActevateEvent(
|
||||||
selectedActivate: selectedItems,
|
selectedActivate: selectedItems,
|
||||||
sortOrder: _blocRole.currentSortOrder));
|
sortOrder: _blocRole.currentSortStatus));
|
||||||
},
|
},
|
||||||
onSortAtoZ: (v) {
|
onSortAtoZ: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortStatus = v;
|
||||||
},
|
},
|
||||||
onSortZtoA: (v) {
|
onSortZtoA: (v) {
|
||||||
_blocRole.currentSortOrder = v;
|
_blocRole.currentSortStatus = v;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -410,7 +419,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
return [
|
return [
|
||||||
Text('${user.firstName} ${user.lastName}'),
|
Text('${user.firstName} ${user.lastName}'),
|
||||||
Text(user.email),
|
Text(user.email),
|
||||||
Text(user.jobTitle ?? '-'),
|
Text(user.jobTitle),
|
||||||
Text(user.roleType ?? ''),
|
Text(user.roleType ?? ''),
|
||||||
Text(user.createdDate ?? ''),
|
Text(user.createdDate ?? ''),
|
||||||
Text(user.createdTime ?? ''),
|
Text(user.createdTime ?? ''),
|
||||||
@ -427,11 +436,6 @@ class UsersPage extends StatelessWidget {
|
|||||||
userId: user.uuid,
|
userId: user.uuid,
|
||||||
onTap: user.status != "invited"
|
onTap: user.status != "invited"
|
||||||
? () {
|
? () {
|
||||||
// final newStatus = user.status == 'active'
|
|
||||||
// ? 'disabled'
|
|
||||||
// : user.status == 'disabled'
|
|
||||||
// ? 'invited'
|
|
||||||
// : 'active';
|
|
||||||
context.read<UserTableBloc>().add(
|
context.read<UserTableBloc>().add(
|
||||||
ChangeUserStatus(
|
ChangeUserStatus(
|
||||||
userId: user.uuid,
|
userId: user.uuid,
|
||||||
@ -443,18 +447,17 @@ class UsersPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
// actionButton(
|
user.isEnabled != false
|
||||||
// title: "Activity Log",
|
? actionButton(
|
||||||
// onTap: () {},
|
isActive: true,
|
||||||
// ),
|
|
||||||
actionButton(
|
|
||||||
title: "Edit",
|
title: "Edit",
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return EditUserDialog(userId: user.uuid);
|
return EditUserDialog(
|
||||||
|
userId: user.uuid);
|
||||||
},
|
},
|
||||||
).then((v) {
|
).then((v) {
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
@ -464,6 +467,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
: actionButton(
|
||||||
|
title: "Edit",
|
||||||
),
|
),
|
||||||
actionButton(
|
actionButton(
|
||||||
title: "Delete",
|
title: "Delete",
|
||||||
@ -486,11 +492,9 @@ class UsersPage extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
).then((v) {
|
).then((v) {
|
||||||
if (v != null) {
|
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
_blocRole.add(const GetUsers());
|
_blocRole.add(const GetUsers());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -516,12 +520,11 @@ class UsersPage extends StatelessWidget {
|
|||||||
const Icon(Icons.keyboard_double_arrow_right),
|
const Icon(Icons.keyboard_double_arrow_right),
|
||||||
firstPageIcon:
|
firstPageIcon:
|
||||||
const Icon(Icons.keyboard_double_arrow_left),
|
const Icon(Icons.keyboard_double_arrow_left),
|
||||||
totalPages: (_blocRole.users.length /
|
totalPages: (_blocRole.totalUsersCount.length /
|
||||||
_blocRole.itemsPerPage)
|
_blocRole.itemsPerPage)
|
||||||
.ceil(),
|
.ceil(),
|
||||||
currentPage: _blocRole.currentPage,
|
currentPage: _blocRole.currentPage,
|
||||||
onPageChanged: (int pageNumber) {
|
onPageChanged: (int pageNumber) {
|
||||||
_blocRole.currentPage = pageNumber;
|
|
||||||
context
|
context
|
||||||
.read<UserTableBloc>()
|
.read<UserTableBloc>()
|
||||||
.add(ChangePage(pageNumber));
|
.add(ChangePage(pageNumber));
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_state.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_state.dart';
|
||||||
|
|||||||
@ -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 'dart:async';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
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/routines/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_state.dart';
|
||||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||||
|
|
||||||
class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
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';
|
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||||
|
|
||||||
abstract class EffectPeriodEvent extends Equatable {
|
abstract class EffectPeriodEvent extends Equatable {
|
||||||
@ -2,7 +2,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
|
|
||||||
part 'functions_bloc_event.dart';
|
part 'functions_bloc_event.dart';
|
||||||
part 'functions_bloc_state.dart';
|
part 'functions_bloc_state.dart';
|
||||||
@ -26,8 +26,7 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
|||||||
functionCode: event.functionData.functionCode,
|
functionCode: event.functionData.functionCode,
|
||||||
operationName: event.functionData.operationName,
|
operationName: event.functionData.operationName,
|
||||||
value: event.functionData.value ?? existingData.value,
|
value: event.functionData.value ?? existingData.value,
|
||||||
valueDescription: event.functionData.valueDescription ??
|
valueDescription: event.functionData.valueDescription ?? existingData.valueDescription,
|
||||||
existingData.valueDescription,
|
|
||||||
condition: event.functionData.condition ?? existingData.condition,
|
condition: event.functionData.condition ?? existingData.condition,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -59,10 +58,8 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onSelectFunction(
|
FutureOr<void> _onSelectFunction(SelectFunction event, Emitter<FunctionBlocState> emit) {
|
||||||
SelectFunction event, Emitter<FunctionBlocState> emit) {
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
selectedFunction: event.functionCode,
|
selectedFunction: event.functionCode, selectedOperationName: event.operationName));
|
||||||
selectedOperationName: event.operationName));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,24 +3,31 @@ import 'dart:async';
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.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/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/routines/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_scene_model.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/delay/delay_fucntions.dart';
|
import 'package:syncrow_web/pages/routines/models/delay/delay_fucntions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/routine_details_model.dart';
|
import 'package:syncrow_web/pages/routines/models/routine_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/routine_model.dart';
|
import 'package:syncrow_web/pages/routines/models/routine_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
import 'package:syncrow_web/services/routines_api.dart';
|
import 'package:syncrow_web/services/routines_api.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
|
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
part 'routine_event.dart';
|
part 'routine_event.dart';
|
||||||
part 'routine_state.dart';
|
part 'routine_state.dart';
|
||||||
|
|
||||||
const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
// String spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||||
const communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
// String communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||||
|
|
||||||
class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||||
RoutineBloc() : super(const RoutineState()) {
|
RoutineBloc() : super(const RoutineState()) {
|
||||||
@ -54,11 +61,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
TriggerSwitchTabsEvent event,
|
TriggerSwitchTabsEvent event,
|
||||||
Emitter<RoutineState> emit,
|
Emitter<RoutineState> emit,
|
||||||
) {
|
) {
|
||||||
emit(state.copyWith(routineTab: event.isRoutineTab, createRoutineView: false));
|
emit(state.copyWith(
|
||||||
|
routineTab: event.isRoutineTab, createRoutineView: false));
|
||||||
add(ResetRoutineState());
|
add(ResetRoutineState());
|
||||||
if (event.isRoutineTab) {
|
if (event.isRoutineTab) {
|
||||||
add(const LoadScenes(spaceId, communityId));
|
add(const LoadScenes());
|
||||||
add(const LoadAutomation(spaceId));
|
add(const LoadAutomation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,8 +88,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
final updatedIfItems = List<Map<String, dynamic>>.from(state.ifItems);
|
final updatedIfItems = List<Map<String, dynamic>>.from(state.ifItems);
|
||||||
|
|
||||||
// Find the index of the item in teh current itemsList
|
// Find the index of the item in teh current itemsList
|
||||||
int index =
|
int index = updatedIfItems.indexWhere(
|
||||||
updatedIfItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||||
// Replace the map if the index is valid
|
// Replace the map if the index is valid
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
updatedIfItems[index] = event.item;
|
updatedIfItems[index] = event.item;
|
||||||
@ -90,18 +98,21 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.isTabToRun) {
|
if (event.isTabToRun) {
|
||||||
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
|
emit(state.copyWith(
|
||||||
|
ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
|
||||||
} else {
|
} else {
|
||||||
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
|
emit(state.copyWith(
|
||||||
|
ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAddToThenContainer(AddToThenContainer event, Emitter<RoutineState> emit) {
|
void _onAddToThenContainer(
|
||||||
|
AddToThenContainer event, Emitter<RoutineState> emit) {
|
||||||
final currentItems = List<Map<String, dynamic>>.from(state.thenItems);
|
final currentItems = List<Map<String, dynamic>>.from(state.thenItems);
|
||||||
|
|
||||||
// Find the index of the item in teh current itemsList
|
// Find the index of the item in teh current itemsList
|
||||||
int index =
|
int index = currentItems.indexWhere(
|
||||||
currentItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||||
// Replace the map if the index is valid
|
// Replace the map if the index is valid
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
currentItems[index] = event.item;
|
currentItems[index] = event.item;
|
||||||
@ -112,22 +123,26 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
emit(state.copyWith(thenItems: currentItems));
|
emit(state.copyWith(thenItems: currentItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
void _onAddFunctionsToRoutine(
|
||||||
|
AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
||||||
try {
|
try {
|
||||||
if (event.functions.isEmpty) return;
|
if (event.functions.isEmpty) return;
|
||||||
|
|
||||||
List<DeviceFunctionData> selectedFunction = List<DeviceFunctionData>.from(event.functions);
|
List<DeviceFunctionData> selectedFunction =
|
||||||
|
List<DeviceFunctionData>.from(event.functions);
|
||||||
|
|
||||||
Map<String, List<DeviceFunctionData>> currentSelectedFunctions =
|
Map<String, List<DeviceFunctionData>> currentSelectedFunctions =
|
||||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||||
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
|
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
|
||||||
List<DeviceFunctionData> currentFunctions =
|
List<DeviceFunctionData> currentFunctions =
|
||||||
List<DeviceFunctionData>.from(currentSelectedFunctions[event.uniqueCustomId] ?? []);
|
List<DeviceFunctionData>.from(
|
||||||
|
currentSelectedFunctions[event.uniqueCustomId] ?? []);
|
||||||
|
|
||||||
List<String> functionCode = [];
|
List<String> functionCode = [];
|
||||||
for (int i = 0; i < selectedFunction.length; i++) {
|
for (int i = 0; i < selectedFunction.length; i++) {
|
||||||
for (int j = 0; j < currentFunctions.length; j++) {
|
for (int j = 0; j < currentFunctions.length; j++) {
|
||||||
if (selectedFunction[i].functionCode == currentFunctions[j].functionCode) {
|
if (selectedFunction[i].functionCode ==
|
||||||
|
currentFunctions[j].functionCode) {
|
||||||
currentFunctions[j] = selectedFunction[i];
|
currentFunctions[j] = selectedFunction[i];
|
||||||
if (!functionCode.contains(currentFunctions[j].functionCode)) {
|
if (!functionCode.contains(currentFunctions[j].functionCode)) {
|
||||||
functionCode.add(currentFunctions[j].functionCode);
|
functionCode.add(currentFunctions[j].functionCode);
|
||||||
@ -137,13 +152,15 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < functionCode.length; i++) {
|
for (int i = 0; i < functionCode.length; i++) {
|
||||||
selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]);
|
selectedFunction
|
||||||
|
.removeWhere((code) => code.functionCode == functionCode[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions)
|
currentSelectedFunctions[event.uniqueCustomId] =
|
||||||
..addAll(selectedFunction);
|
List.from(currentFunctions)..addAll(selectedFunction);
|
||||||
} else {
|
} else {
|
||||||
currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions);
|
currentSelectedFunctions[event.uniqueCustomId] =
|
||||||
|
List.from(event.functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
|
emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
|
||||||
@ -152,11 +169,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onLoadScenes(LoadScenes event, Emitter<RoutineState> emit) async {
|
Future<void> _onLoadScenes(
|
||||||
|
LoadScenes event, Emitter<RoutineState> emit) async {
|
||||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||||
|
List<ScenesModel> scenes = [];
|
||||||
try {
|
try {
|
||||||
final scenes = await SceneApi.getScenesByUnitId(event.unitId, event.communityId);
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
|
List<String> spacesList =
|
||||||
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
|
for (var spaceId in spacesList) {
|
||||||
|
scenes.addAll(
|
||||||
|
await SceneApi.getScenes(spaceId, communityId, projectUuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
scenes: scenes,
|
scenes: scenes,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@ -167,46 +197,49 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
loadScenesErrorMessage: 'Failed to load scenes',
|
loadScenesErrorMessage: 'Failed to load scenes',
|
||||||
errorMessage: '',
|
errorMessage: '',
|
||||||
loadAutomationErrorMessage: '',
|
loadAutomationErrorMessage: '',
|
||||||
));
|
scenes: scenes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onLoadAutomation(LoadAutomation event, Emitter<RoutineState> emit) async {
|
Future<void> _onLoadAutomation(
|
||||||
|
LoadAutomation event, Emitter<RoutineState> emit) async {
|
||||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||||
|
List<ScenesModel> automations = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final automations = await SceneApi.getAutomationByUnitId(event.unitId);
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
if (automations.isNotEmpty) {
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
|
List<String> spacesList =
|
||||||
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
|
for (var spaceId in spacesList) {
|
||||||
|
automations.addAll(await SceneApi.getAutomation(spaceId));
|
||||||
|
}
|
||||||
|
}
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
automations: automations,
|
automations: automations,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
));
|
));
|
||||||
} else {
|
|
||||||
emit(state.copyWith(
|
|
||||||
isLoading: false,
|
|
||||||
loadAutomationErrorMessage: 'Failed to load automations',
|
|
||||||
errorMessage: '',
|
|
||||||
loadScenesErrorMessage: '',
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
loadAutomationErrorMessage: 'Failed to load automations',
|
loadAutomationErrorMessage: 'Failed to load automations',
|
||||||
errorMessage: '',
|
errorMessage: '',
|
||||||
loadScenesErrorMessage: '',
|
loadScenesErrorMessage: '',
|
||||||
));
|
automations: automations));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onSearchRoutines(SearchRoutines event, Emitter<RoutineState> emit) async {
|
FutureOr<void> _onSearchRoutines(
|
||||||
|
SearchRoutines event, Emitter<RoutineState> emit) async {
|
||||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
emit(state.copyWith(isLoading: false, errorMessage: null));
|
emit(state.copyWith(isLoading: false, errorMessage: null));
|
||||||
emit(state.copyWith(searchText: event.query));
|
emit(state.copyWith(searchText: event.query));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onAddSelectedIcon(AddSelectedIcon event, Emitter<RoutineState> emit) {
|
FutureOr<void> _onAddSelectedIcon(
|
||||||
|
AddSelectedIcon event, Emitter<RoutineState> emit) {
|
||||||
emit(state.copyWith(selectedIcon: event.icon));
|
emit(state.copyWith(selectedIcon: event.icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +253,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
return actions.last['deviceId'] == 'delay';
|
return actions.last['deviceId'] == 'delay';
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onCreateScene(CreateSceneEvent event, Emitter<RoutineState> emit) async {
|
Future<void> _onCreateScene(
|
||||||
|
CreateSceneEvent event, Emitter<RoutineState> emit) async {
|
||||||
try {
|
try {
|
||||||
// Check if first action is delay
|
// Check if first action is delay
|
||||||
// if (_isFirstActionDelay(state.thenItems)) {
|
// if (_isFirstActionDelay(state.thenItems)) {
|
||||||
@ -233,7 +267,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
|
|
||||||
if (_isLastActionDelay(state.thenItems)) {
|
if (_isLastActionDelay(state.thenItems)) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
errorMessage:
|
||||||
|
'A delay condition cannot be the only or the last action',
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
@ -278,8 +313,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
});
|
});
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
|
|
||||||
final createSceneModel = CreateSceneModel(
|
final createSceneModel = CreateSceneModel(
|
||||||
spaceUuid: spaceId,
|
spaceUuid: spaceBloc.state.selectedSpaces[0],
|
||||||
iconId: state.selectedIcon ?? '',
|
iconId: state.selectedIcon ?? '',
|
||||||
showInDevice: true,
|
showInDevice: true,
|
||||||
sceneName: state.routineName ?? '',
|
sceneName: state.routineName ?? '',
|
||||||
@ -290,8 +328,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
final result = await SceneApi.createScene(createSceneModel);
|
final result = await SceneApi.createScene(createSceneModel);
|
||||||
if (result['success']) {
|
if (result['success']) {
|
||||||
add(ResetRoutineState());
|
add(ResetRoutineState());
|
||||||
add(const LoadScenes(spaceId, communityId));
|
add(const LoadScenes());
|
||||||
add(const LoadAutomation(spaceId));
|
add(const LoadAutomation());
|
||||||
} else {
|
} else {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@ -306,7 +344,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onCreateAutomation(CreateAutomationEvent event, Emitter<RoutineState> emit) async {
|
Future<void> _onCreateAutomation(
|
||||||
|
CreateAutomationEvent event, Emitter<RoutineState> emit) async {
|
||||||
try {
|
try {
|
||||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
@ -327,7 +366,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
|
|
||||||
if (_isLastActionDelay(state.thenItems)) {
|
if (_isLastActionDelay(state.thenItems)) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
errorMessage:
|
||||||
|
'A delay condition cannot be the only or the last action',
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
));
|
));
|
||||||
CustomSnackBar.redSnackBar('Cannot have delay as the last action');
|
CustomSnackBar.redSnackBar('Cannot have delay as the last action');
|
||||||
@ -402,9 +442,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}).toList();
|
}).toList();
|
||||||
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
|
|
||||||
final createAutomationModel = CreateAutomationModel(
|
final createAutomationModel = CreateAutomationModel(
|
||||||
spaceUuid: spaceId,
|
spaceUuid: spaceBloc.state.selectedSpaces[0],
|
||||||
automationName: state.routineName ?? '',
|
automationName: state.routineName ?? '',
|
||||||
decisionExpr: state.selectedAutomationOperator,
|
decisionExpr: state.selectedAutomationOperator,
|
||||||
effectiveTime: EffectiveTime(
|
effectiveTime: EffectiveTime(
|
||||||
@ -419,8 +461,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
final result = await SceneApi.createAutomation(createAutomationModel);
|
final result = await SceneApi.createAutomation(createAutomationModel);
|
||||||
if (result['success']) {
|
if (result['success']) {
|
||||||
add(ResetRoutineState());
|
add(ResetRoutineState());
|
||||||
add(const LoadAutomation(spaceId));
|
add(const LoadAutomation());
|
||||||
add(const LoadScenes(spaceId, communityId));
|
add(const LoadScenes());
|
||||||
} else {
|
} else {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@ -437,17 +479,21 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onRemoveDragCard(RemoveDragCard event, Emitter<RoutineState> emit) {
|
FutureOr<void> _onRemoveDragCard(
|
||||||
|
RemoveDragCard event, Emitter<RoutineState> emit) {
|
||||||
if (event.isFromThen) {
|
if (event.isFromThen) {
|
||||||
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
|
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
|
||||||
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
final selectedFunctions =
|
||||||
|
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||||
|
|
||||||
thenItems.removeAt(event.index);
|
thenItems.removeAt(event.index);
|
||||||
selectedFunctions.remove(event.key);
|
selectedFunctions.remove(event.key);
|
||||||
emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions));
|
emit(state.copyWith(
|
||||||
|
thenItems: thenItems, selectedFunctions: selectedFunctions));
|
||||||
} else {
|
} else {
|
||||||
final ifItems = List<Map<String, dynamic>>.from(state.ifItems);
|
final ifItems = List<Map<String, dynamic>>.from(state.ifItems);
|
||||||
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
final selectedFunctions =
|
||||||
|
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||||
|
|
||||||
ifItems.removeAt(event.index);
|
ifItems.removeAt(event.index);
|
||||||
selectedFunctions.remove(event.key);
|
selectedFunctions.remove(event.key);
|
||||||
@ -458,7 +504,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
isAutomation: false,
|
isAutomation: false,
|
||||||
isTabToRun: false));
|
isTabToRun: false));
|
||||||
} else {
|
} else {
|
||||||
emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions));
|
emit(state.copyWith(
|
||||||
|
ifItems: ifItems, selectedFunctions: selectedFunctions));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,18 +517,23 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
|
FutureOr<void> _onEffectiveTimeEvent(
|
||||||
|
EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
|
||||||
emit(state.copyWith(effectiveTime: event.effectiveTime));
|
emit(state.copyWith(effectiveTime: event.effectiveTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onSetRoutineName(SetRoutineName event, Emitter<RoutineState> emit) {
|
FutureOr<void> _onSetRoutineName(
|
||||||
|
SetRoutineName event, Emitter<RoutineState> emit) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
routineName: event.name,
|
routineName: event.name,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
(List<Map<String, dynamic>>, List<Map<String, dynamic>>, Map<String, List<DeviceFunctionData>>)
|
(
|
||||||
_createCardData(
|
List<Map<String, dynamic>>,
|
||||||
|
List<Map<String, dynamic>>,
|
||||||
|
Map<String, List<DeviceFunctionData>>
|
||||||
|
) _createCardData(
|
||||||
List<RoutineAction> actions,
|
List<RoutineAction> actions,
|
||||||
List<RoutineCondition>? conditions,
|
List<RoutineCondition>? conditions,
|
||||||
Map<String, List<DeviceFunctionData>> currentFunctions,
|
Map<String, List<DeviceFunctionData>> currentFunctions,
|
||||||
@ -514,7 +566,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
'deviceId': condition.entityId,
|
'deviceId': condition.entityId,
|
||||||
'title': matchingDevice.name ?? condition.entityId,
|
'title': matchingDevice.name ?? condition.entityId,
|
||||||
'productType': condition.entityType,
|
'productType': condition.entityType,
|
||||||
'imagePath': matchingDevice.getDefaultIcon(condition.entityType),
|
'imagePath':
|
||||||
|
matchingDevice.getDefaultIcon(condition.entityType),
|
||||||
};
|
};
|
||||||
|
|
||||||
final functions = matchingDevice.functions;
|
final functions = matchingDevice.functions;
|
||||||
@ -550,8 +603,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
final cardData = {
|
final cardData = {
|
||||||
'entityId': action.entityId,
|
'entityId': action.entityId,
|
||||||
'uniqueCustomId': const Uuid().v4(),
|
'uniqueCustomId': const Uuid().v4(),
|
||||||
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
'deviceId':
|
||||||
'title': action.actionExecutor == 'delay' ? 'Delay' : (matchingDevice.name ?? 'Device'),
|
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||||
|
'title': action.actionExecutor == 'delay'
|
||||||
|
? 'Delay'
|
||||||
|
: (matchingDevice.name ?? 'Device'),
|
||||||
'productType': action.productType,
|
'productType': action.productType,
|
||||||
'imagePath': matchingDevice.getDefaultIcon(action.productType),
|
'imagePath': matchingDevice.getDefaultIcon(action.productType),
|
||||||
};
|
};
|
||||||
@ -594,7 +650,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
return (thenItems, ifItems, currentFunctions);
|
return (thenItems, ifItems, currentFunctions);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onGetSceneDetails(GetSceneDetails event, Emitter<RoutineState> emit) async {
|
Future<void> _onGetSceneDetails(
|
||||||
|
GetSceneDetails event, Emitter<RoutineState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
@ -642,8 +699,10 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
if (!deviceCards.containsKey(deviceId)) {
|
if (!deviceCards.containsKey(deviceId)) {
|
||||||
deviceCards[deviceId] = {
|
deviceCards[deviceId] = {
|
||||||
'entityId': action.entityId,
|
'entityId': action.entityId,
|
||||||
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
'deviceId':
|
||||||
'uniqueCustomId': action.type == 'automation' || action.actionExecutor == 'delay'
|
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||||
|
'uniqueCustomId':
|
||||||
|
action.type == 'automation' || action.actionExecutor == 'delay'
|
||||||
? const Uuid().v4()
|
? const Uuid().v4()
|
||||||
: action.entityId,
|
: action.entityId,
|
||||||
'title': action.actionExecutor == 'delay'
|
'title': action.actionExecutor == 'delay'
|
||||||
@ -680,7 +739,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
// emit(state.copyWith(automationActionExecutor: action.actionExecutor));
|
// emit(state.copyWith(automationActionExecutor: action.actionExecutor));
|
||||||
} else if (action.executorProperty != null && action.actionExecutor != 'delay') {
|
} else if (action.executorProperty != null &&
|
||||||
|
action.actionExecutor != 'delay') {
|
||||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
||||||
updatedFunctions[uniqueCustomId] = [];
|
updatedFunctions[uniqueCustomId] = [];
|
||||||
}
|
}
|
||||||
@ -752,7 +812,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onResetRoutineState(ResetRoutineState event, Emitter<RoutineState> emit) {
|
FutureOr<void> _onResetRoutineState(
|
||||||
|
ResetRoutineState event, Emitter<RoutineState> emit) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
ifItems: [],
|
ifItems: [],
|
||||||
thenItems: [],
|
thenItems: [],
|
||||||
@ -776,17 +837,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
createRoutineView: false));
|
createRoutineView: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _deleteScene(DeleteScene event, Emitter<RoutineState> emit) {
|
FutureOr<void> _deleteScene(
|
||||||
|
DeleteScene event, Emitter<RoutineState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(state.copyWith(isLoading: true));
|
emit(state.copyWith(isLoading: true));
|
||||||
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
if (state.isTabToRun) {
|
if (state.isTabToRun) {
|
||||||
SceneApi.deleteScene(unitUuid: spaceId, sceneId: state.sceneId ?? '');
|
await SceneApi.deleteScene(
|
||||||
|
unitUuid: spaceBloc.state.selectedSpaces[0],
|
||||||
|
sceneId: state.sceneId ?? '');
|
||||||
} else {
|
} else {
|
||||||
SceneApi.deleteAutomation(unitUuid: spaceId, automationId: state.automationId ?? '');
|
await SceneApi.deleteAutomation(
|
||||||
|
unitUuid: spaceBloc.state.selectedSpaces[0],
|
||||||
|
automationId: state.automationId ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
add(const LoadScenes(spaceId, communityId));
|
add(const LoadScenes());
|
||||||
add(const LoadAutomation(spaceId));
|
add(const LoadAutomation());
|
||||||
add(ResetRoutineState());
|
add(ResetRoutineState());
|
||||||
emit(state.copyWith(isLoading: false, createRoutineView: false));
|
emit(state.copyWith(isLoading: false, createRoutineView: false));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -811,10 +879,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
FutureOr<void> _fetchDevices(FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
|
FutureOr<void> _fetchDevices(
|
||||||
|
FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
|
||||||
emit(state.copyWith(isLoading: true));
|
emit(state.copyWith(isLoading: true));
|
||||||
try {
|
try {
|
||||||
final devices = await DevicesManagementApi().fetchDevices();
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
List<AllDevicesModel> devices = [];
|
||||||
|
|
||||||
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
|
List<String> spacesList =
|
||||||
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
|
for (var spaceId in spacesList) {
|
||||||
|
devices.addAll(await DevicesManagementApi()
|
||||||
|
.fetchDevices(communityId, spaceId, projectUuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit(state.copyWith(isLoading: false, devices: devices));
|
emit(state.copyWith(isLoading: false, devices: devices));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -822,7 +904,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onUpdateScene(UpdateScene event, Emitter<RoutineState> emit) async {
|
FutureOr<void> _onUpdateScene(
|
||||||
|
UpdateScene event, Emitter<RoutineState> emit) async {
|
||||||
try {
|
try {
|
||||||
// Check if first action is delay
|
// Check if first action is delay
|
||||||
// if (_isFirstActionDelay(state.thenItems)) {
|
// if (_isFirstActionDelay(state.thenItems)) {
|
||||||
@ -836,7 +919,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
|
|
||||||
if (_isLastActionDelay(state.thenItems)) {
|
if (_isLastActionDelay(state.thenItems)) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
errorMessage:
|
||||||
|
'A delay condition cannot be the only or the last action',
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
@ -889,11 +973,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
actions: actions,
|
actions: actions,
|
||||||
);
|
);
|
||||||
|
|
||||||
final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
|
final result =
|
||||||
|
await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
|
||||||
if (result['success']) {
|
if (result['success']) {
|
||||||
add(ResetRoutineState());
|
add(ResetRoutineState());
|
||||||
add(const LoadScenes(spaceId, communityId));
|
add(const LoadScenes());
|
||||||
add(const LoadAutomation(spaceId));
|
add(const LoadAutomation());
|
||||||
} else {
|
} else {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@ -908,7 +993,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onUpdateAutomation(UpdateAutomation event, Emitter<RoutineState> emit) async {
|
FutureOr<void> _onUpdateAutomation(
|
||||||
|
UpdateAutomation event, Emitter<RoutineState> emit) async {
|
||||||
try {
|
try {
|
||||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
@ -1003,8 +1089,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
});
|
});
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
|
|
||||||
final createAutomationModel = CreateAutomationModel(
|
final createAutomationModel = CreateAutomationModel(
|
||||||
spaceUuid: spaceId,
|
spaceUuid: spaceBloc.state.selectedSpaces[0],
|
||||||
automationName: state.routineName ?? '',
|
automationName: state.routineName ?? '',
|
||||||
decisionExpr: state.selectedAutomationOperator,
|
decisionExpr: state.selectedAutomationOperator,
|
||||||
effectiveTime: EffectiveTime(
|
effectiveTime: EffectiveTime(
|
||||||
@ -1016,13 +1105,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
actions: actions,
|
actions: actions,
|
||||||
);
|
);
|
||||||
|
|
||||||
final result =
|
final result = await SceneApi.updateAutomation(
|
||||||
await SceneApi.updateAutomation(createAutomationModel, state.automationId ?? '');
|
createAutomationModel, state.automationId ?? '');
|
||||||
|
|
||||||
if (result['success']) {
|
if (result['success']) {
|
||||||
add(ResetRoutineState());
|
add(ResetRoutineState());
|
||||||
add(const LoadAutomation(spaceId));
|
add(LoadAutomation());
|
||||||
add(const LoadScenes(spaceId, communityId));
|
add(LoadScenes());
|
||||||
} else {
|
} else {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@ -1050,7 +1139,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
thenItems: [],
|
thenItems: [],
|
||||||
));
|
));
|
||||||
|
|
||||||
final automationDetails = await SceneApi.getAutomationDetails(event.automationId);
|
final automationDetails =
|
||||||
|
await SceneApi.getAutomationDetails(event.automationId);
|
||||||
|
|
||||||
final Map<String, Map<String, dynamic>> deviceIfCards = {};
|
final Map<String, Map<String, dynamic>> deviceIfCards = {};
|
||||||
final Map<String, Map<String, dynamic>> deviceThenCards = {};
|
final Map<String, Map<String, dynamic>> deviceThenCards = {};
|
||||||
@ -1118,13 +1208,15 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final deviceId =
|
final deviceId = action.actionExecutor == 'delay'
|
||||||
action.actionExecutor == 'delay' ? '${action.entityId}_delay' : action.entityId;
|
? '${action.entityId}_delay'
|
||||||
|
: action.entityId;
|
||||||
|
|
||||||
if (!deviceThenCards.containsKey(deviceId)) {
|
if (!deviceThenCards.containsKey(deviceId)) {
|
||||||
deviceThenCards[deviceId] = {
|
deviceThenCards[deviceId] = {
|
||||||
'entityId': action.entityId,
|
'entityId': action.entityId,
|
||||||
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
'deviceId':
|
||||||
|
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||||
'uniqueCustomId': const Uuid().v4(),
|
'uniqueCustomId': const Uuid().v4(),
|
||||||
'title': action.actionExecutor == 'delay'
|
'title': action.actionExecutor == 'delay'
|
||||||
? 'Delay'
|
? 'Delay'
|
||||||
@ -1155,7 +1247,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
updatedFunctions[uniqueCustomId] = [];
|
updatedFunctions[uniqueCustomId] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.executorProperty != null && action.actionExecutor != 'delay') {
|
if (action.executorProperty != null &&
|
||||||
|
action.actionExecutor != 'delay') {
|
||||||
final functions = matchingDevice.functions;
|
final functions = matchingDevice.functions;
|
||||||
final functionCode = action.executorProperty!.functionCode;
|
final functionCode = action.executorProperty!.functionCode;
|
||||||
for (var function in functions) {
|
for (var function in functions) {
|
||||||
@ -1197,10 +1290,14 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ifItems = deviceIfCards.values.where((card) => card['type'] == 'condition').toList();
|
final ifItems = deviceIfCards.values
|
||||||
|
.where((card) => card['type'] == 'condition')
|
||||||
|
.toList();
|
||||||
final thenItems = deviceThenCards.values
|
final thenItems = deviceThenCards.values
|
||||||
.where((card) =>
|
.where((card) =>
|
||||||
card['type'] == 'action' || card['type'] == 'automation' || card['type'] == 'scene')
|
card['type'] == 'action' ||
|
||||||
|
card['type'] == 'automation' ||
|
||||||
|
card['type'] == 'scene')
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
@ -27,22 +27,24 @@ class AddToThenContainer extends RoutineEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class LoadScenes extends RoutineEvent {
|
class LoadScenes extends RoutineEvent {
|
||||||
final String unitId;
|
// final String spaceId;
|
||||||
final String communityId;
|
// final String communityId;
|
||||||
|
// final BuildContext context;
|
||||||
|
|
||||||
const LoadScenes(this.unitId, this.communityId);
|
const LoadScenes();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [unitId, communityId];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class LoadAutomation extends RoutineEvent {
|
class LoadAutomation extends RoutineEvent {
|
||||||
final String unitId;
|
// final String spaceId;
|
||||||
|
// final BuildContext context;
|
||||||
|
|
||||||
const LoadAutomation(this.unitId);
|
const LoadAutomation();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [unitId];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddFunctionToRoutine extends RoutineEvent {
|
class AddFunctionToRoutine extends RoutineEvent {
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_event.dart';
|
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_event.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_state.dart';
|
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_state.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
import 'package:syncrow_web/pages/routines/models/icon_model.dart';
|
||||||
import 'package:syncrow_web/services/routines_api.dart';
|
import 'package:syncrow_web/services/routines_api.dart';
|
||||||
|
|
||||||
class SettingBloc extends Bloc<SettingEvent, SettingState> {
|
class SettingBloc extends Bloc<SettingEvent, SettingState> {
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
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 {
|
abstract class SettingState extends Equatable {
|
||||||
const SettingState();
|
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/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.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/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
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/routines/models/ac/ac_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.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/app_enum.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.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/routines/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/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class DelayFunction extends BaseSwitchFunction {
|
class DelayFunction extends BaseSwitchFunction {
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||||
|
|
||||||
abstract class BaseSwitchFunction extends DeviceFunction<bool> {
|
abstract class BaseSwitchFunction extends DeviceFunction<bool> {
|
||||||
BaseSwitchFunction({
|
BaseSwitchFunction({
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routines/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/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class OneGangSwitchFunction extends BaseSwitchFunction {
|
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/routines/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/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class ThreeGangSwitch1Function extends BaseSwitchFunction {
|
class ThreeGangSwitch1Function extends BaseSwitchFunction {
|
||||||
@ -26,8 +26,7 @@ class ThreeGangSwitch1Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangCountdown1Function extends BaseSwitchFunction {
|
class ThreeGangCountdown1Function extends BaseSwitchFunction {
|
||||||
ThreeGangCountdown1Function(
|
ThreeGangCountdown1Function({required super.deviceId, required super.deviceName})
|
||||||
{required super.deviceId, required super.deviceName})
|
|
||||||
: super(
|
: super(
|
||||||
code: 'countdown_1',
|
code: 'countdown_1',
|
||||||
operationName: 'Light 1 Countdown',
|
operationName: 'Light 1 Countdown',
|
||||||
@ -71,8 +70,7 @@ class ThreeGangSwitch2Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangCountdown2Function extends BaseSwitchFunction {
|
class ThreeGangCountdown2Function extends BaseSwitchFunction {
|
||||||
ThreeGangCountdown2Function(
|
ThreeGangCountdown2Function({required super.deviceId, required super.deviceName})
|
||||||
{required super.deviceId, required super.deviceName})
|
|
||||||
: super(
|
: super(
|
||||||
code: 'countdown_2',
|
code: 'countdown_2',
|
||||||
operationName: 'Light 2 Countdown',
|
operationName: 'Light 2 Countdown',
|
||||||
@ -116,8 +114,7 @@ class ThreeGangSwitch3Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangCountdown3Function extends BaseSwitchFunction {
|
class ThreeGangCountdown3Function extends BaseSwitchFunction {
|
||||||
ThreeGangCountdown3Function(
|
ThreeGangCountdown3Function({required super.deviceId, required super.deviceName})
|
||||||
{required super.deviceId, required super.deviceName})
|
|
||||||
: super(
|
: super(
|
||||||
code: 'countdown_3',
|
code: 'countdown_3',
|
||||||
operationName: 'Light 3 Countdown',
|
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/routines/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/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class TwoGangSwitch1Function extends BaseSwitchFunction {
|
class TwoGangSwitch1Function extends BaseSwitchFunction {
|
||||||
@ -49,8 +49,7 @@ class TwoGangSwitch2Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TwoGangCountdown1Function extends BaseSwitchFunction {
|
class TwoGangCountdown1Function extends BaseSwitchFunction {
|
||||||
TwoGangCountdown1Function(
|
TwoGangCountdown1Function({required super.deviceId, required super.deviceName})
|
||||||
{required super.deviceId, required super.deviceName})
|
|
||||||
: super(
|
: super(
|
||||||
code: 'countdown_1',
|
code: 'countdown_1',
|
||||||
operationName: 'Light 1 Countdown',
|
operationName: 'Light 1 Countdown',
|
||||||
@ -71,8 +70,7 @@ class TwoGangCountdown1Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TwoGangCountdown2Function extends BaseSwitchFunction {
|
class TwoGangCountdown2Function extends BaseSwitchFunction {
|
||||||
TwoGangCountdown2Function(
|
TwoGangCountdown2Function({required super.deviceId, required super.deviceName})
|
||||||
{required super.deviceId, required super.deviceName})
|
|
||||||
: super(
|
: super(
|
||||||
code: 'countdown_2',
|
code: 'countdown_2',
|
||||||
operationName: 'Light 2 Countdown',
|
operationName: 'Light 2 Countdown',
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
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/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart';
|
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||||
|
|
||||||
class RoutineDetailsModel {
|
class RoutineDetailsModel {
|
||||||
final String spaceUuid;
|
final String spaceUuid;
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/conditions_routines_devices_view.dart';
|
import 'package:syncrow_web/pages/routines/widgets/conditions_routines_devices_view.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/if_container.dart';
|
import 'package:syncrow_web/pages/routines/widgets/if_container.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_search_and_buttons.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_search_and_buttons.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/then_container.dart';
|
import 'package:syncrow_web/pages/routines/widgets/then_container.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class CreateNewRoutineView extends StatelessWidget {
|
class CreateNewRoutineView extends StatelessWidget {
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/effictive_period_dialog.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/effictive_period_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/period_option.dart';
|
import 'package:syncrow_web/pages/routines/widgets/period_option.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/repeat_days.dart';
|
import 'package:syncrow_web/pages/routines/widgets/repeat_days.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class EffectivePeriodView extends StatelessWidget {
|
class EffectivePeriodView extends StatelessWidget {
|
||||||
105
lib/pages/routines/view/routines_view.dart
Normal file
105
lib/pages/routines/view/routines_view.dart
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
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: () {
|
||||||
|
context.read<RoutineBloc>()
|
||||||
|
..add(const LoadScenes())
|
||||||
|
..add(const LoadAutomation());
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
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>().state.selectedCommunities.length == 1 &&
|
||||||
|
context.read<SpaceTreeBloc>().state.selectedSpaces.length == 1) {
|
||||||
|
context.read<RoutineBloc>().add(
|
||||||
|
(ResetRoutineState()),
|
||||||
|
);
|
||||||
|
BlocProvider.of<RoutineBloc>(context).add(
|
||||||
|
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
context.read<SpaceTreeBloc>().state.selectedSpaces.isEmpty
|
||||||
|
? 'Please select a space'
|
||||||
|
: 'Please select only one space to proceed'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// CustomSnackBar.redSnackBar(
|
||||||
|
// context.read<SpaceTreeBloc>().state.selectedSpaces.isEmpty
|
||||||
|
// ? 'Please select a space'
|
||||||
|
// : 'Please select only one space to proceed');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: Icons.add,
|
||||||
|
textString: '',
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
const Expanded(child: FetchRoutineScenesAutomation()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_devices.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_devices.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routines_title_widget.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routines_title_widget.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/scenes_and_automations.dart';
|
import 'package:syncrow_web/pages/routines/widgets/scenes_and_automations.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/search_bar_condition_title.dart';
|
import 'package:syncrow_web/pages/routines/widgets/search_bar_condition_title.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class ConditionsRoutinesDevicesView extends StatelessWidget {
|
class ConditionsRoutinesDevicesView extends StatelessWidget {
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/common/custom_dialog.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';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class DeleteSceneWidget extends StatelessWidget {
|
class DeleteSceneWidget extends StatelessWidget {
|
||||||
@ -3,8 +3,8 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.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/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/helper/dialog_helper/device_dialog_helper.dart';
|
import 'package:syncrow_web/pages/routines/helper/dialog_helper/device_dialog_helper.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
@ -26,9 +26,7 @@ class IfContainer extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Text('IF',
|
const Text('IF', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18, fontWeight: FontWeight.bold)),
|
|
||||||
if (state.isAutomation && state.ifItems.isNotEmpty)
|
if (state.isAutomation && state.ifItems.isNotEmpty)
|
||||||
AutomationOperatorSelector(
|
AutomationOperatorSelector(
|
||||||
selectedOperator: state.selectedAutomationOperator),
|
selectedOperator: state.selectedAutomationOperator),
|
||||||
@ -55,44 +53,34 @@ class IfContainer extends StatelessWidget {
|
|||||||
(index) => GestureDetector(
|
(index) => GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (!state.isTabToRun) {
|
if (!state.isTabToRun) {
|
||||||
final result = await DeviceDialogHelper
|
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||||
.showDeviceDialog(
|
|
||||||
context, state.ifItems[index],
|
context, state.ifItems[index],
|
||||||
removeComparetors: false);
|
removeComparetors: false);
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
context.read<RoutineBloc>().add(
|
context
|
||||||
AddToIfContainer(
|
.read<RoutineBloc>()
|
||||||
state.ifItems[index], false));
|
.add(AddToIfContainer(state.ifItems[index], false));
|
||||||
} else if (![
|
} else if (!['AC', '1G', '2G', '3G']
|
||||||
'AC',
|
.contains(state.ifItems[index]['productType'])) {
|
||||||
'1G',
|
context
|
||||||
'2G',
|
.read<RoutineBloc>()
|
||||||
'3G'
|
.add(AddToIfContainer(state.ifItems[index], false));
|
||||||
].contains(
|
|
||||||
state.ifItems[index]['productType'])) {
|
|
||||||
context.read<RoutineBloc>().add(
|
|
||||||
AddToIfContainer(
|
|
||||||
state.ifItems[index], false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: DraggableCard(
|
child: DraggableCard(
|
||||||
imagePath:
|
imagePath: state.ifItems[index]['imagePath'] ?? '',
|
||||||
state.ifItems[index]['imagePath'] ?? '',
|
|
||||||
title: state.ifItems[index]['title'] ?? '',
|
title: state.ifItems[index]['title'] ?? '',
|
||||||
deviceData: state.ifItems[index],
|
deviceData: state.ifItems[index],
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
|
||||||
horizontal: 4, vertical: 8),
|
|
||||||
isFromThen: false,
|
isFromThen: false,
|
||||||
isFromIf: true,
|
isFromIf: true,
|
||||||
onRemove: () {
|
onRemove: () {
|
||||||
context.read<RoutineBloc>().add(
|
context.read<RoutineBloc>().add(RemoveDragCard(
|
||||||
RemoveDragCard(
|
|
||||||
index: index,
|
index: index,
|
||||||
isFromThen: false,
|
isFromThen: false,
|
||||||
key: state.ifItems[index]
|
key: state.ifItems[index]['uniqueCustomId']));
|
||||||
['uniqueCustomId']));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
@ -113,23 +101,15 @@ class IfContainer extends StatelessWidget {
|
|||||||
|
|
||||||
if (!state.isTabToRun) {
|
if (!state.isTabToRun) {
|
||||||
if (mutableData['deviceId'] == 'tab_to_run') {
|
if (mutableData['deviceId'] == 'tab_to_run') {
|
||||||
context
|
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, true));
|
||||||
.read<RoutineBloc>()
|
|
||||||
.add(AddToIfContainer(mutableData, true));
|
|
||||||
} else {
|
} else {
|
||||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData,
|
||||||
context, mutableData,
|
|
||||||
removeComparetors: false);
|
removeComparetors: false);
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
context
|
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||||
.read<RoutineBloc>()
|
} else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) {
|
||||||
.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: () {
|
onPressed: () {
|
||||||
context
|
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'or'));
|
||||||
.read<RoutineBloc>()
|
|
||||||
.add(const ChangeAutomationOperator(operator: 'or'));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
@ -203,9 +181,7 @@ class AutomationOperatorSelector extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context
|
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'and'));
|
||||||
.read<RoutineBloc>()
|
|
||||||
.add(const ChangeAutomationOperator(operator: 'and'));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,
|
height: iconSize,
|
||||||
width: iconSize,
|
width: iconSize,
|
||||||
child: (isFromScenes ?? false)
|
child: (isFromScenes ?? false)
|
||||||
? (iconInBytes != null &&
|
? (iconInBytes != null && iconInBytes?.isNotEmpty == true)
|
||||||
iconInBytes?.isNotEmpty == true)
|
|
||||||
? Image.memory(
|
? Image.memory(
|
||||||
iconInBytes!,
|
iconInBytes!,
|
||||||
height: iconSize,
|
height: iconSize,
|
||||||
width: iconSize,
|
width: iconSize,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
errorBuilder: (context, error, stackTrace) =>
|
errorBuilder: (context, error, stackTrace) => Image.asset(
|
||||||
Image.asset(
|
|
||||||
Assets.logo,
|
Assets.logo,
|
||||||
height: iconSize,
|
height: iconSize,
|
||||||
width: iconSize,
|
width: iconSize,
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
import 'package:syncrow_web/pages/routines/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_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_state.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/effictive_period_dialog.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/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||||
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
import 'package:syncrow_web/pages/routines/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_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_state.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class RepeatDays extends StatelessWidget {
|
class RepeatDays extends StatelessWidget {
|
||||||
@ -1,12 +1,23 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.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/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||||
|
|
||||||
class RoutineDevices extends StatelessWidget {
|
class RoutineDevices extends StatefulWidget {
|
||||||
const RoutineDevices({super.key});
|
const RoutineDevices({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RoutineDevices> createState() => _RoutineDevicesState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RoutineDevicesState extends State<RoutineDevices> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||||
@ -35,9 +46,7 @@ class RoutineDevices extends StatelessWidget {
|
|||||||
children: deviceList.asMap().entries.map((entry) {
|
children: deviceList.asMap().entries.map((entry) {
|
||||||
final device = entry.value;
|
final device = entry.value;
|
||||||
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
||||||
return device.name!
|
return device.name!.toLowerCase().contains(state.searchText!.toLowerCase())
|
||||||
.toLowerCase()
|
|
||||||
.contains(state.searchText!.toLowerCase())
|
|
||||||
? DraggableCard(
|
? DraggableCard(
|
||||||
imagePath: device.getDefaultIcon(device.productType),
|
imagePath: device.getDefaultIcon(device.productType),
|
||||||
title: device.name ?? '',
|
title: device.name ?? '',
|
||||||
@ -1,16 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.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/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/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_function.dart';
|
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/ac/ac_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.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 {
|
class ACHelper {
|
||||||
static Future<Map<String, dynamic>?> showACFunctionsDialog(
|
static Future<Map<String, dynamic>?> showACFunctionsDialog(
|
||||||
@ -27,16 +27,15 @@ class ACHelper {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FunctionBloc()
|
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final selectedFunction = state.selectedFunction;
|
final selectedFunction = state.selectedFunction;
|
||||||
final selectedOperationName = state.selectedOperationName;
|
final selectedOperationName = state.selectedOperationName;
|
||||||
final selectedFunctionData = state.addedFunctions
|
final selectedFunctionData =
|
||||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction ?? '',
|
functionCode: selectedFunction ?? '',
|
||||||
@ -66,10 +65,8 @@ class ACHelper {
|
|||||||
child: _buildFunctionsList(
|
child: _buildFunctionsList(
|
||||||
context: context,
|
context: context,
|
||||||
acFunctions: acFunctions,
|
acFunctions: acFunctions,
|
||||||
onFunctionSelected:
|
onFunctionSelected: (functionCode, operationName) =>
|
||||||
(functionCode, operationName) => context
|
context.read<FunctionBloc>().add(SelectFunction(
|
||||||
.read<FunctionBloc>()
|
|
||||||
.add(SelectFunction(
|
|
||||||
functionCode: functionCode,
|
functionCode: functionCode,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
)),
|
)),
|
||||||
@ -184,7 +181,7 @@ class ACHelper {
|
|||||||
bool? removeComparators,
|
bool? removeComparators,
|
||||||
}) {
|
}) {
|
||||||
if (selectedFunction == 'temp_set' || selectedFunction == 'temp_current') {
|
if (selectedFunction == 'temp_set' || selectedFunction == 'temp_current') {
|
||||||
final initialValue = selectedFunctionData?.value ?? 200;
|
final initialValue = selectedFunctionData?.value ?? 250;
|
||||||
return _buildTemperatureSelector(
|
return _buildTemperatureSelector(
|
||||||
context: context,
|
context: context,
|
||||||
initialValue: initialValue,
|
initialValue: initialValue,
|
||||||
@ -197,8 +194,7 @@ class ACHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn =
|
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
acFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -294,8 +290,7 @@ class ACHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected:
|
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -333,10 +328,10 @@ class ACHelper {
|
|||||||
String selectCode,
|
String selectCode,
|
||||||
) {
|
) {
|
||||||
return Slider(
|
return Slider(
|
||||||
value: initialValue is int ? initialValue.toDouble() : 160.0,
|
value: initialValue is int ? initialValue.toDouble() : 200.0,
|
||||||
min: 160,
|
min: 200,
|
||||||
max: 300,
|
max: 300,
|
||||||
divisions: 14,
|
divisions: 10,
|
||||||
label: '${((initialValue ?? 160) / 10).toInt()}°C',
|
label: '${((initialValue ?? 160) / 10).toInt()}°C',
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
@ -389,13 +384,9 @@ class ACHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected
|
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||||
? Icons.radio_button_checked
|
|
||||||
: Icons.radio_button_unchecked,
|
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||||
? ColorsManager.primaryColorWithOpacity
|
|
||||||
: ColorsManager.textGray,
|
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
@ -407,8 +398,7 @@ class ACHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription:
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
selectedFunctionData?.valueDescription,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.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/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class AutomationDialog extends StatefulWidget {
|
class AutomationDialog extends StatefulWidget {
|
||||||
@ -31,10 +31,8 @@ class _AutomationDialogState extends State<AutomationDialog> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
List<DeviceFunctionData>? functions = context
|
List<DeviceFunctionData>? functions =
|
||||||
.read<RoutineBloc>()
|
context.read<RoutineBloc>().state.selectedFunctions[widget.uniqueCustomId];
|
||||||
.state
|
|
||||||
.selectedFunctions[widget.uniqueCustomId];
|
|
||||||
for (DeviceFunctionData data in functions ?? []) {
|
for (DeviceFunctionData data in functions ?? []) {
|
||||||
if (data.entityId == widget.automationId) {
|
if (data.entityId == widget.automationId) {
|
||||||
selectedAutomationActionExecutor = data.value;
|
selectedAutomationActionExecutor = data.value;
|
||||||
@ -67,8 +65,7 @@ class _AutomationDialogState extends State<AutomationDialog> {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading:
|
leading: SvgPicture.asset(Assets.acPowerOff, width: 24, height: 24),
|
||||||
SvgPicture.asset(Assets.acPowerOff, width: 24, height: 24),
|
|
||||||
title: const Text('Disable'),
|
title: const Text('Disable'),
|
||||||
trailing: Radio<String?>(
|
trailing: Radio<String?>(
|
||||||
value: 'rule_disable',
|
value: 'rule_disable',
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
|
|
||||||
class DelayHelper {
|
class DelayHelper {
|
||||||
static Future<Map<String, dynamic>?> showDelayPickerDialog(
|
static Future<Map<String, dynamic>?> showDelayPickerDialog(
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/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/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
import 'package:syncrow_web/pages/routines/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_event.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.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_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.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/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/routines/bloc/functions_bloc/functions_bloc_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/pages/routiens/helper/duration_format_helper.dart';
|
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routines/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/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@ -22,23 +22,21 @@ class OneGangSwitchHelper {
|
|||||||
String uniqueCustomId,
|
String uniqueCustomId,
|
||||||
bool removeComparetors,
|
bool removeComparetors,
|
||||||
) async {
|
) async {
|
||||||
List<BaseSwitchFunction> acFunctions =
|
List<BaseSwitchFunction> acFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
||||||
functions.whereType<BaseSwitchFunction>().toList();
|
|
||||||
|
|
||||||
return showDialog<Map<String, dynamic>?>(
|
return showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FunctionBloc()
|
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final selectedFunction = state.selectedFunction;
|
final selectedFunction = state.selectedFunction;
|
||||||
final selectedOperationName = state.selectedOperationName;
|
final selectedOperationName = state.selectedOperationName;
|
||||||
final selectedFunctionData = state.addedFunctions
|
final selectedFunctionData =
|
||||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction ?? '',
|
functionCode: selectedFunction ?? '',
|
||||||
@ -85,12 +83,9 @@ class OneGangSwitchHelper {
|
|||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context
|
context.read<FunctionBloc>().add(SelectFunction(
|
||||||
.read<FunctionBloc>()
|
|
||||||
.add(SelectFunction(
|
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
operationName:
|
operationName: function.operationName,
|
||||||
function.operationName,
|
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -180,8 +175,7 @@ class OneGangSwitchHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn =
|
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
acFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -218,11 +212,11 @@ class OneGangSwitchHelper {
|
|||||||
selectedFunctionData,
|
selectedFunctionData,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
_buildCountDownDisplay(
|
||||||
selectedFunctionData, selectCode),
|
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
_buildCountDownSlider(
|
||||||
selectedFunctionData, selectCode),
|
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -263,8 +257,7 @@ class OneGangSwitchHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected:
|
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -312,8 +305,7 @@ class OneGangSwitchHelper {
|
|||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: (((operationalValues.maxValue ?? 0) -
|
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||||
(operationalValues.minValue ?? 0)) /
|
|
||||||
(operationalValues.stepValue ?? 1))
|
(operationalValues.stepValue ?? 1))
|
||||||
.round(),
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -365,13 +357,9 @@ class OneGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected
|
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||||
? Icons.radio_button_checked
|
|
||||||
: Icons.radio_button_unchecked,
|
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||||
? ColorsManager.primaryColorWithOpacity
|
|
||||||
: ColorsManager.textGray,
|
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
@ -383,8 +371,7 @@ class OneGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription:
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
selectedFunctionData?.valueDescription,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1,17 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
import 'package:syncrow_web/pages/routines/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_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_state.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/routiens/bloc/setting_bloc/setting_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_event.dart';
|
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_event.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_state.dart';
|
import 'package:syncrow_web/pages/routines/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/routines/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
import 'package:syncrow_web/pages/routines/models/icon_model.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/view/effective_period_view.dart';
|
import 'package:syncrow_web/pages/routines/view/effective_period_view.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/delete_scene.dart';
|
import 'package:syncrow_web/pages/routines/widgets/delete_scene.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:flutter/cupertino.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_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.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/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/routines/bloc/functions_bloc/functions_bloc_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/pages/routiens/helper/duration_format_helper.dart';
|
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routines/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/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@ -22,23 +22,21 @@ class ThreeGangSwitchHelper {
|
|||||||
String uniqueCustomId,
|
String uniqueCustomId,
|
||||||
bool removeComparetors,
|
bool removeComparetors,
|
||||||
) async {
|
) async {
|
||||||
List<BaseSwitchFunction> switchFunctions =
|
List<BaseSwitchFunction> switchFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
||||||
functions.whereType<BaseSwitchFunction>().toList();
|
|
||||||
|
|
||||||
return showDialog<Map<String, dynamic>?>(
|
return showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FunctionBloc()
|
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final selectedFunction = state.selectedFunction;
|
final selectedFunction = state.selectedFunction;
|
||||||
final selectedOperationName = state.selectedOperationName;
|
final selectedOperationName = state.selectedOperationName;
|
||||||
final selectedFunctionData = state.addedFunctions
|
final selectedFunctionData =
|
||||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction ?? '',
|
functionCode: selectedFunction ?? '',
|
||||||
@ -85,12 +83,9 @@ class ThreeGangSwitchHelper {
|
|||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context
|
context.read<FunctionBloc>().add(SelectFunction(
|
||||||
.read<FunctionBloc>()
|
|
||||||
.add(SelectFunction(
|
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
operationName:
|
operationName: function.operationName,
|
||||||
function.operationName,
|
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -182,8 +177,7 @@ class ThreeGangSwitchHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn =
|
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -220,11 +214,11 @@ class ThreeGangSwitchHelper {
|
|||||||
selectedFunctionData,
|
selectedFunctionData,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
_buildCountDownDisplay(
|
||||||
selectedFunctionData, selectCode),
|
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
_buildCountDownSlider(
|
||||||
selectedFunctionData, selectCode),
|
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -265,8 +259,7 @@ class ThreeGangSwitchHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected:
|
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -314,8 +307,7 @@ class ThreeGangSwitchHelper {
|
|||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: (((operationalValues.maxValue ?? 0) -
|
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||||
(operationalValues.minValue ?? 0)) /
|
|
||||||
(operationalValues.stepValue ?? 1))
|
(operationalValues.stepValue ?? 1))
|
||||||
.round(),
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -367,13 +359,9 @@ class ThreeGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected
|
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||||
? Icons.radio_button_checked
|
|
||||||
: Icons.radio_button_unchecked,
|
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||||
? ColorsManager.primaryColorWithOpacity
|
|
||||||
: ColorsManager.textGray,
|
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
@ -385,8 +373,7 @@ class ThreeGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription:
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
selectedFunctionData?.valueDescription,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.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/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/routines/bloc/functions_bloc/functions_bloc_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/pages/routiens/helper/duration_format_helper.dart';
|
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routines/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/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@ -22,23 +22,21 @@ class TwoGangSwitchHelper {
|
|||||||
String uniqueCustomId,
|
String uniqueCustomId,
|
||||||
bool removeComparetors,
|
bool removeComparetors,
|
||||||
) async {
|
) async {
|
||||||
List<BaseSwitchFunction> switchFunctions =
|
List<BaseSwitchFunction> switchFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
||||||
functions.whereType<BaseSwitchFunction>().toList();
|
|
||||||
|
|
||||||
return showDialog<Map<String, dynamic>?>(
|
return showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FunctionBloc()
|
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final selectedFunction = state.selectedFunction;
|
final selectedFunction = state.selectedFunction;
|
||||||
final selectedOperationName = state.selectedOperationName;
|
final selectedOperationName = state.selectedOperationName;
|
||||||
final selectedFunctionData = state.addedFunctions
|
final selectedFunctionData =
|
||||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction ?? '',
|
functionCode: selectedFunction ?? '',
|
||||||
@ -85,12 +83,9 @@ class TwoGangSwitchHelper {
|
|||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context
|
context.read<FunctionBloc>().add(SelectFunction(
|
||||||
.read<FunctionBloc>()
|
|
||||||
.add(SelectFunction(
|
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
operationName:
|
operationName: function.operationName,
|
||||||
function.operationName,
|
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -166,8 +161,7 @@ class TwoGangSwitchHelper {
|
|||||||
required String operationName,
|
required String operationName,
|
||||||
required bool removeComparetors,
|
required bool removeComparetors,
|
||||||
}) {
|
}) {
|
||||||
if (selectedFunction == 'countdown_1' ||
|
if (selectedFunction == 'countdown_1' || selectedFunction == 'countdown_2') {
|
||||||
selectedFunction == 'countdown_2') {
|
|
||||||
final initialValue = selectedFunctionData?.value ?? 200;
|
final initialValue = selectedFunctionData?.value ?? 200;
|
||||||
return _buildTemperatureSelector(
|
return _buildTemperatureSelector(
|
||||||
context: context,
|
context: context,
|
||||||
@ -181,8 +175,7 @@ class TwoGangSwitchHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn =
|
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -219,11 +212,11 @@ class TwoGangSwitchHelper {
|
|||||||
selectedFunctionData,
|
selectedFunctionData,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
_buildCountDownDisplay(
|
||||||
selectedFunctionData, selectCode),
|
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
_buildCountDownSlider(
|
||||||
selectedFunctionData, selectCode),
|
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -264,8 +257,7 @@ class TwoGangSwitchHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected:
|
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -313,8 +305,7 @@ class TwoGangSwitchHelper {
|
|||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: (((operationalValues.maxValue ?? 0) -
|
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||||
(operationalValues.minValue ?? 0)) /
|
|
||||||
(operationalValues.stepValue ?? 1))
|
(operationalValues.stepValue ?? 1))
|
||||||
.round(),
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -366,13 +357,9 @@ class TwoGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected
|
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||||
? Icons.radio_button_checked
|
|
||||||
: Icons.radio_button_unchecked,
|
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||||
? ColorsManager.primaryColorWithOpacity
|
|
||||||
: ColorsManager.textGray,
|
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
@ -384,8 +371,7 @@ class TwoGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription:
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
selectedFunctionData?.valueDescription,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.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/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/helper/save_routine_helper.dart';
|
import 'package:syncrow_web/pages/routines/helper/save_routine_helper.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/discard_dialog.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/discard_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/setting_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/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class ScenesAndAutomations extends StatefulWidget {
|
class ScenesAndAutomations extends StatefulWidget {
|
||||||
@ -18,8 +18,8 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
context.read<RoutineBloc>()
|
context.read<RoutineBloc>()
|
||||||
..add(const LoadScenes(spaceId, communityId))
|
..add(const LoadScenes())
|
||||||
..add(const LoadAutomation(spaceId));
|
..add(const LoadAutomation());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -34,9 +34,7 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
|
|||||||
children: scenes.asMap().entries.map((entry) {
|
children: scenes.asMap().entries.map((entry) {
|
||||||
final scene = entry.value;
|
final scene = entry.value;
|
||||||
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
||||||
return scene.name
|
return scene.name.toLowerCase().contains(state.searchText!.toLowerCase())
|
||||||
.toLowerCase()
|
|
||||||
.contains(state.searchText!.toLowerCase())
|
|
||||||
? DraggableCard(
|
? DraggableCard(
|
||||||
imagePath: scene.icon ?? Assets.loginLogo,
|
imagePath: scene.icon ?? Assets.loginLogo,
|
||||||
title: scene.name,
|
title: scene.name,
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/common/text_field/custom_text_field.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/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/routines_title_widget.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/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user