mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-11 07:38:05 +00:00
Compare commits
99 Commits
bugfix/edi
...
bugfix/fix
Author | SHA1 | Date | |
---|---|---|---|
fe4e775902 | |||
5247856cb4 | |||
4a8b8a32ba | |||
2abce77eb5 | |||
7efd1c3c87 | |||
7a0d9aefb7 | |||
21cc25cfc4 | |||
e2ec4bbf31 | |||
51b46ae197 | |||
0c2a092f4d | |||
b968b5a6eb | |||
05edc7641a | |||
b8204f1015 | |||
d87fec796b | |||
b00b0c82dc | |||
0aa029a2fc | |||
dec3a25639 | |||
581dcf7016 | |||
e1609309cf | |||
da445e11aa | |||
55de7fab0f | |||
36ee22603a | |||
b0abd42b0c | |||
ba4da78846 | |||
a623f1c723 | |||
c5f5992c18 | |||
dc20d69f20 | |||
98ad7090d8 | |||
ea08024b82 | |||
cf6ec231dc | |||
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 | |||
64e3fb7f34 | |||
e6e46be9b4 | |||
91dfd53477 | |||
5ab9664318 | |||
d3bf4de0ca | |||
5ae07688cb | |||
e6fa9c2391 | |||
916b606cb1 | |||
29c444eede | |||
9dd6c9e1e7 | |||
b070884bd9 | |||
bf5b39e742 | |||
7d05a33c52 | |||
6e546a4831 | |||
b098202fd8 | |||
a294988558 | |||
43c17d1c18 | |||
09c1a785e5 | |||
e70b9ea9e2 | |||
c173df934d | |||
e4262d08a5 | |||
4bae7bb9fb | |||
073916d4ac | |||
8870467fe4 | |||
9331193e90 | |||
45b0b67fe0 | |||
9e0184f19d | |||
ea5b6597f5 | |||
2221d9ae7b | |||
921d352207 | |||
c5871be990 | |||
2fb6f30ccb | |||
508d8bbaa8 | |||
97bdb1bbb7 | |||
7ce0a27af0 | |||
bc4af6a237 | |||
513175ed1e | |||
5060d2a66d | |||
540f569b1f | |||
a98f7e77a3 | |||
0341844ea9 | |||
d0530f7fc3 |
@ -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,13 +48,16 @@ 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) {
|
||||||
_isOpen = false;
|
_overlayEntry!.remove();
|
||||||
|
_overlayEntry = null;
|
||||||
|
_isOpen = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayEntry _createOverlayEntry() {
|
OverlayEntry _createOverlayEntry() {
|
||||||
@ -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,40 +80,44 @@ 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(
|
|
||||||
decoration: const BoxDecoration(
|
return Container(
|
||||||
border: Border(
|
decoration: const BoxDecoration(
|
||||||
bottom: BorderSide(
|
border: Border(
|
||||||
color: ColorsManager.lightGrayBorderColor,
|
bottom: BorderSide(
|
||||||
width: 1.0,
|
color: ColorsManager.lightGrayBorderColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
child: ListTile(
|
||||||
),
|
title: Text(item,
|
||||||
child: ListTile(
|
style: Theme.of(context)
|
||||||
title: Text(item,
|
.textTheme
|
||||||
style: Theme.of(context)
|
.bodyMedium
|
||||||
.textTheme
|
?.copyWith(
|
||||||
.bodyMedium
|
color: ColorsManager
|
||||||
?.copyWith(
|
.textPrimaryColor)),
|
||||||
color: ColorsManager.textPrimaryColor)),
|
onTap: () {
|
||||||
onTap: () {
|
_controller.text = item;
|
||||||
_controller.text = item;
|
widget.onSelected(item);
|
||||||
widget.onSelected(item);
|
setState(() {
|
||||||
setState(() {
|
_filteredItems
|
||||||
_filteredItems
|
.remove(item); // Remove selected item
|
||||||
.remove(item); // Remove selected item
|
});
|
||||||
});
|
_closeDropdown();
|
||||||
_closeDropdown();
|
},
|
||||||
},
|
),
|
||||||
),
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -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,24 +51,24 @@ 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,
|
),
|
||||||
),
|
|
||||||
suffixIcon: Padding(
|
suffixIcon: Padding(
|
||||||
padding: const EdgeInsets.only(right: 16),
|
padding: const EdgeInsets.only(right: 16),
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
@ -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));
|
||||||
@ -88,8 +93,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
|||||||
return Theme(
|
return Theme(
|
||||||
data: ThemeData.light().copyWith(
|
data: ThemeData.light().copyWith(
|
||||||
colorScheme: ColorScheme.light(
|
colorScheme: ColorScheme.light(
|
||||||
primary: ColorsManager.blackColor,
|
primary: ColorsManager.blackColor,
|
||||||
onPrimary: Colors.white,
|
onPrimary: Colors.white,
|
||||||
onSurface: ColorsManager.grayColor,
|
onSurface: ColorsManager.grayColor,
|
||||||
),
|
),
|
||||||
textButtonTheme: TextButtonThemeData(
|
textButtonTheme: TextButtonThemeData(
|
||||||
|
@ -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,6 +9,7 @@ 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/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';
|
||||||
@ -31,7 +32,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
|
|
||||||
////////////////////////////// forget password //////////////////////////////////
|
////////////////////////////// forget password //////////////////////////////////
|
||||||
final TextEditingController forgetEmailController = TextEditingController();
|
final TextEditingController forgetEmailController = TextEditingController();
|
||||||
final TextEditingController forgetPasswordController = TextEditingController();
|
final TextEditingController forgetPasswordController =
|
||||||
|
TextEditingController();
|
||||||
final TextEditingController forgetOtp = TextEditingController();
|
final TextEditingController forgetOtp = TextEditingController();
|
||||||
final forgetFormKey = GlobalKey<FormState>();
|
final forgetFormKey = GlobalKey<FormState>();
|
||||||
final forgetEmailKey = GlobalKey<FormState>();
|
final forgetEmailKey = GlobalKey<FormState>();
|
||||||
@ -48,7 +50,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_remainingTime = 1;
|
_remainingTime = 1;
|
||||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
add(UpdateTimerEvent(
|
||||||
|
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||||
try {
|
try {
|
||||||
forgetEmailValidate = '';
|
forgetEmailValidate = '';
|
||||||
_remainingTime = (await AuthenticationAPI.sendOtp(
|
_remainingTime = (await AuthenticationAPI.sendOtp(
|
||||||
@ -85,7 +88,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
||||||
} else {
|
} else {
|
||||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
add(UpdateTimerEvent(
|
||||||
|
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -95,7 +99,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
|
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> changePassword(ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
Future<void> changePassword(
|
||||||
|
ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||||
emit(LoadingForgetState());
|
emit(LoadingForgetState());
|
||||||
try {
|
try {
|
||||||
var response = await AuthenticationAPI.verifyOtp(
|
var response = await AuthenticationAPI.verifyOtp(
|
||||||
@ -111,7 +116,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
}
|
}
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
final errorData = e.response!.data;
|
final errorData = e.response!.data;
|
||||||
String errorMessage = errorData['error']['message'] ?? 'something went wrong';
|
String errorMessage =
|
||||||
|
errorData['error']['message'] ?? 'something went wrong';
|
||||||
validate = errorMessage;
|
validate = errorMessage;
|
||||||
emit(AuthInitialState());
|
emit(AuthInitialState());
|
||||||
}
|
}
|
||||||
@ -125,7 +131,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
|
void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
|
||||||
emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime));
|
emit(TimerState(
|
||||||
|
isButtonEnabled: event.isButtonEnabled,
|
||||||
|
remainingTime: event.remainingTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////// login /////////////////////////////////////
|
///////////////////////////////////// login /////////////////////////////////////
|
||||||
@ -161,15 +169,22 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
password: event.password,
|
password: event.password,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (failure) {
|
} on DioException catch (e) {
|
||||||
validate = 'Invalid Credentials!';
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage = errorData['error']['message'];
|
||||||
|
if (errorMessage == "Access denied for web platform") {
|
||||||
|
validate = errorMessage;
|
||||||
|
} else {
|
||||||
|
validate = 'Invalid Credentials!';
|
||||||
|
}
|
||||||
emit(LoginInitial());
|
emit(LoginInitial());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.accessTokenIsNotEmpty) {
|
if (token.accessTokenIsNotEmpty) {
|
||||||
FlutterSecureStorage storage = const FlutterSecureStorage();
|
FlutterSecureStorage storage = const FlutterSecureStorage();
|
||||||
await storage.write(key: Token.loginAccessTokenKey, value: token.accessToken);
|
await storage.write(
|
||||||
|
key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||||
const FlutterSecureStorage().write(
|
const FlutterSecureStorage().write(
|
||||||
key: UserModel.userUuidKey,
|
key: UserModel.userUuidKey,
|
||||||
value: Token.decodeToken(token.accessToken)['uuid'].toString());
|
value: Token.decodeToken(token.accessToken)['uuid'].toString());
|
||||||
@ -327,12 +342,14 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
static Future<String> getTokenAndValidate() async {
|
static Future<String> getTokenAndValidate() async {
|
||||||
try {
|
try {
|
||||||
const storage = FlutterSecureStorage();
|
const storage = FlutterSecureStorage();
|
||||||
final firstLaunch =
|
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
|
||||||
await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
|
StringsManager.firstLaunch) ??
|
||||||
|
true;
|
||||||
if (firstLaunch) {
|
if (firstLaunch) {
|
||||||
storage.deleteAll();
|
storage.deleteAll();
|
||||||
}
|
}
|
||||||
await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
|
await SharedPreferencesHelper.saveBoolToSP(
|
||||||
|
StringsManager.firstLaunch, false);
|
||||||
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
|
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
|
||||||
if (value.isEmpty) {
|
if (value.isEmpty) {
|
||||||
return 'Token not found';
|
return 'Token not found';
|
||||||
@ -385,7 +402,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||||||
final String formattedTime = [
|
final String formattedTime = [
|
||||||
if (days > 0) '${days}d', // Append 'd' for days
|
if (days > 0) '${days}d', // Append 'd' for days
|
||||||
if (days > 0 || hours > 0)
|
if (days > 0 || hours > 0)
|
||||||
hours.toString().padLeft(2, '0'), // Show hours if there are days or hours
|
hours
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0'), // Show hours if there are days or hours
|
||||||
minutes.toString().padLeft(2, '0'),
|
minutes.toString().padLeft(2, '0'),
|
||||||
seconds.toString().padLeft(2, '0'),
|
seconds.toString().padLeft(2, '0'),
|
||||||
].join(':');
|
].join(':');
|
||||||
@ -423,8 +442,9 @@ 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();
|
||||||
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;
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
class DeviceSubspace {
|
||||||
|
final String uuid;
|
||||||
|
final DateTime? createdAt;
|
||||||
|
final DateTime? updatedAt;
|
||||||
|
final String subspaceName;
|
||||||
|
final bool disabled;
|
||||||
|
|
||||||
|
DeviceSubspace({
|
||||||
|
required this.uuid,
|
||||||
|
this.createdAt,
|
||||||
|
this.updatedAt,
|
||||||
|
required this.subspaceName,
|
||||||
|
required this.disabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory DeviceSubspace.fromJson(Map<String, dynamic> json) {
|
||||||
|
return DeviceSubspace(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
createdAt: json['createdAt'] != null
|
||||||
|
? DateTime.tryParse(json['createdAt'].toString())
|
||||||
|
: null,
|
||||||
|
updatedAt: json['updatedAt'] != null
|
||||||
|
? DateTime.tryParse(json['updatedAt'].toString())
|
||||||
|
: null,
|
||||||
|
subspaceName: json['subspaceName'] as String,
|
||||||
|
disabled: json['disabled'] as bool,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'createdAt': createdAt?.toIso8601String(),
|
||||||
|
'updatedAt': updatedAt?.toIso8601String(),
|
||||||
|
'subspaceName': subspaceName,
|
||||||
|
'disabled': disabled,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<DeviceSubspace> listFromJson(List<dynamic> jsonList) {
|
||||||
|
return jsonList.map((json) => DeviceSubspace.fromJson(json)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Map<String, dynamic>> listToJson(List<DeviceSubspace> subspaces) {
|
||||||
|
return subspaces.map((subspace) => subspace.toJson()).toList();
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,13 @@
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_community.model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_community.model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_subspace.model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/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';
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ class AllDevicesModel {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
DevicesModelRoom? room;
|
DevicesModelRoom? room;
|
||||||
|
DeviceSubspace? subspace;
|
||||||
DevicesModelUnit? unit;
|
DevicesModelUnit? unit;
|
||||||
DeviceCommunityModel? community;
|
DeviceCommunityModel? community;
|
||||||
String? productUuid;
|
String? productUuid;
|
||||||
@ -77,6 +79,7 @@ class AllDevicesModel {
|
|||||||
|
|
||||||
AllDevicesModel({
|
AllDevicesModel({
|
||||||
this.room,
|
this.room,
|
||||||
|
this.subspace,
|
||||||
this.unit,
|
this.unit,
|
||||||
this.community,
|
this.community,
|
||||||
this.productUuid,
|
this.productUuid,
|
||||||
@ -110,6 +113,9 @@ class AllDevicesModel {
|
|||||||
room = (json['room'] != null && (json['room'] is Map))
|
room = (json['room'] != null && (json['room'] is Map))
|
||||||
? DevicesModelRoom.fromJson(json['room'])
|
? DevicesModelRoom.fromJson(json['room'])
|
||||||
: null;
|
: null;
|
||||||
|
subspace = (json['subspace'] != null && (json['subspace'] is Map))
|
||||||
|
? DeviceSubspace.fromJson(json['subspace'])
|
||||||
|
: null;
|
||||||
unit = (json['unit'] != null && (json['unit'] is Map))
|
unit = (json['unit'] != null && (json['unit'] is Map))
|
||||||
? DevicesModelUnit.fromJson(json['unit'])
|
? DevicesModelUnit.fromJson(json['unit'])
|
||||||
: null;
|
: null;
|
||||||
@ -142,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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,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;
|
||||||
@ -248,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:
|
||||||
@ -288,6 +282,9 @@ SOS
|
|||||||
if (room != null) {
|
if (room != null) {
|
||||||
data['room'] = room!.toJson();
|
data['room'] = room!.toJson();
|
||||||
}
|
}
|
||||||
|
if (subspace != null) {
|
||||||
|
data['subspace'] = subspace!.toJson();
|
||||||
|
}
|
||||||
if (unit != null) {
|
if (unit != null) {
|
||||||
data['unit'] = unit!.toJson();
|
data['unit'] = unit!.toJson();
|
||||||
}
|
}
|
||||||
@ -330,6 +327,7 @@ SOS
|
|||||||
|
|
||||||
return other is AllDevicesModel &&
|
return other is AllDevicesModel &&
|
||||||
other.room == room &&
|
other.room == room &&
|
||||||
|
other.subspace == subspace &&
|
||||||
other.unit == unit &&
|
other.unit == unit &&
|
||||||
other.productUuid == productUuid &&
|
other.productUuid == productUuid &&
|
||||||
other.productType == productType &&
|
other.productType == productType &&
|
||||||
@ -360,6 +358,7 @@ SOS
|
|||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return room.hashCode ^
|
return room.hashCode ^
|
||||||
|
subspace.hashCode ^
|
||||||
unit.hashCode ^
|
unit.hashCode ^
|
||||||
productUuid.hashCode ^
|
productUuid.hashCode ^
|
||||||
productType.hashCode ^
|
productType.hashCode ^
|
||||||
|
@ -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,118 +61,153 @@ 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: [
|
children: [
|
||||||
Container(
|
Expanded(child: SpaceTreeView(
|
||||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
onSelect: () {
|
||||||
child: Column(
|
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
},
|
||||||
children: [
|
)),
|
||||||
FilterWidget(
|
Expanded(
|
||||||
size: MediaQuery.of(context).size,
|
flex: 4,
|
||||||
tabs: tabs,
|
child: state is DeviceManagementLoading
|
||||||
selectedIndex: selectedIndex,
|
? const Center(child: CircularProgressIndicator())
|
||||||
onTabChanged: (index) {
|
: Column(
|
||||||
context.read<DeviceManagementBloc>().add(SelectedFilterChanged(index));
|
children: [
|
||||||
},
|
Container(
|
||||||
),
|
padding: isLargeScreenSize(context)
|
||||||
const SizedBox(height: 20),
|
? const EdgeInsets.all(30)
|
||||||
const DeviceSearchFilters(),
|
: const EdgeInsets.all(15),
|
||||||
const SizedBox(height: 12),
|
child: Column(
|
||||||
Container(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
height: 45,
|
children: [
|
||||||
width: 125,
|
FilterWidget(
|
||||||
decoration: containerDecoration,
|
size: MediaQuery.of(context).size,
|
||||||
child: Center(
|
tabs: tabs,
|
||||||
child: DefaultButton(
|
selectedIndex: selectedIndex,
|
||||||
onPressed: isControlButtonEnabled
|
onTabChanged: (index) {
|
||||||
? () {
|
context
|
||||||
if (selectedDevices.length == 1) {
|
.read<DeviceManagementBloc>()
|
||||||
showDialog(
|
.add(SelectedFilterChanged(index));
|
||||||
context: context,
|
},
|
||||||
builder: (context) => DeviceControlDialog(
|
),
|
||||||
device: selectedDevices.first,
|
const SizedBox(height: 20),
|
||||||
),
|
const DeviceSearchFilters(),
|
||||||
);
|
const SizedBox(height: 12),
|
||||||
} else if (selectedDevices.length > 1) {
|
Container(
|
||||||
final productTypes = selectedDevices.map((device) => device.productType).toSet();
|
height: 45,
|
||||||
if (productTypes.length == 1) {
|
width: 125,
|
||||||
showDialog(
|
decoration: containerDecoration,
|
||||||
context: context,
|
child: Center(
|
||||||
builder: (context) => DeviceBatchControlDialog(
|
child: DefaultButton(
|
||||||
devices: selectedDevices,
|
onPressed: isControlButtonEnabled
|
||||||
|
? () {
|
||||||
|
if (selectedDevices.length == 1) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => DeviceControlDialog(
|
||||||
|
device: selectedDevices.first,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (selectedDevices.length > 1) {
|
||||||
|
final productTypes = selectedDevices
|
||||||
|
.map((device) => device.productType)
|
||||||
|
.toSet();
|
||||||
|
if (productTypes.length == 1) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => DeviceBatchControlDialog(
|
||||||
|
devices: selectedDevices,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
borderRadius: 9,
|
||||||
|
child: Text(
|
||||||
|
buttonLabel,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: isControlButtonEnabled ? Colors.white : Colors.grey,
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
}
|
),
|
||||||
}
|
),
|
||||||
}
|
),
|
||||||
: null,
|
],
|
||||||
borderRadius: 9,
|
|
||||||
child: Text(
|
|
||||||
buttonLabel,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: isControlButtonEnabled ? Colors.white : Colors.grey,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Expanded(
|
||||||
),
|
child: Padding(
|
||||||
),
|
padding: isLargeScreenSize(context)
|
||||||
],
|
? const EdgeInsets.all(30)
|
||||||
),
|
: const EdgeInsets.all(15),
|
||||||
),
|
child: DynamicTable(
|
||||||
Expanded(
|
withSelectAll: true,
|
||||||
child: Padding(
|
cellDecoration: containerDecoration,
|
||||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
onRowSelected: (index, isSelected, row) {
|
||||||
child: DynamicTable(
|
final selectedDevice = devicesToShow[index];
|
||||||
withSelectAll: true,
|
context
|
||||||
cellDecoration: containerDecoration,
|
.read<DeviceManagementBloc>()
|
||||||
onRowSelected: (index, isSelected, row) {
|
.add(SelectDevice(selectedDevice));
|
||||||
final selectedDevice = devicesToShow[index];
|
},
|
||||||
context.read<DeviceManagementBloc>().add(SelectDevice(selectedDevice));
|
withCheckBox: true,
|
||||||
},
|
size: MediaQuery.of(context).size,
|
||||||
withCheckBox: true,
|
uuidIndex: 2,
|
||||||
size: MediaQuery.of(context).size,
|
headers: const [
|
||||||
uuidIndex: 2,
|
'Device Name',
|
||||||
headers: const [
|
'Product Name',
|
||||||
'Device Name',
|
'Device ID',
|
||||||
'Product Name',
|
'Space Name',
|
||||||
'Device ID',
|
'location',
|
||||||
'Space Name',
|
'Battery Level',
|
||||||
'location',
|
'Installation Date and Time',
|
||||||
'Battery Level',
|
'Status',
|
||||||
'Installation Date and Time',
|
'Last Offline Date and Time',
|
||||||
'Status',
|
],
|
||||||
'Last Offline Date and Time',
|
data: devicesToShow.map((device) {
|
||||||
],
|
final combinedSpaceNames = device.spaces != null
|
||||||
data: devicesToShow.map((device) {
|
? device.spaces!.map((space) => space.spaceName).join(' > ') +
|
||||||
final combinedSpaceNames = device.spaces != null
|
(device.community != null
|
||||||
? device.spaces!.map((space) => space.spaceName).join(' > ') +
|
? ' > ${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)
|
||||||
combinedSpaceNames,
|
? device.spaces![0].spaceName
|
||||||
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
: '',
|
||||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
|
combinedSpaceNames,
|
||||||
device.online == true ? 'Online' : 'Offline',
|
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
||||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
|
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||||
];
|
(device.createTime ?? 0) * 1000)),
|
||||||
}).toList(),
|
device.online == true ? 'Online' : 'Offline',
|
||||||
onSelectionChanged: (selectedRows) {
|
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||||
context.read<DeviceManagementBloc>().add(UpdateSelection(selectedRows));
|
(device.updateTime ?? 0) * 1000)),
|
||||||
},
|
];
|
||||||
initialSelectedIds:
|
}).toList(),
|
||||||
context.read<DeviceManagementBloc>().selectedDevices.map((device) => device.uuid!).toList(),
|
onSelectionChanged: (selectedRows) {
|
||||||
isEmpty: devicesToShow.isEmpty,
|
context
|
||||||
),
|
.read<DeviceManagementBloc>()
|
||||||
),
|
.add(UpdateSelection(selectedRows));
|
||||||
)
|
},
|
||||||
|
initialSelectedIds: context
|
||||||
|
.read<DeviceManagementBloc>()
|
||||||
|
.selectedDevices
|
||||||
|
.map((device) => device.uuid!)
|
||||||
|
.toList(),
|
||||||
|
isEmpty: devicesToShow.isEmpty,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -12,8 +12,7 @@ class DeviceSearchFilters extends StatefulWidget {
|
|||||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
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));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,9 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
]),
|
]),
|
||||||
TableRow(
|
TableRow(
|
||||||
children: [
|
children: [
|
||||||
_buildInfoRow('Space Name:', device.unit?.name ?? 'N/A'),
|
_buildInfoRow('Space Name:',
|
||||||
_buildInfoRow('Room:', device.room?.name ?? 'N/A'),
|
device.spaces?.firstOrNull?.spaceName ?? 'N/A'),
|
||||||
|
_buildInfoRow('Room:', device.subspace?.subspaceName ?? 'N/A'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
TableRow(
|
TableRow(
|
||||||
@ -111,9 +112,13 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
),
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
'Battery Level:',
|
'Battery Level:',
|
||||||
device.batteryLevel != null ? '${device.batteryLevel ?? 0}%' : "-",
|
device.batteryLevel != null
|
||||||
|
? '${device.batteryLevel ?? 0}%'
|
||||||
|
: "-",
|
||||||
statusColor: device.batteryLevel != null
|
statusColor: device.batteryLevel != null
|
||||||
? (device.batteryLevel! < 20 ? ColorsManager.red : ColorsManager.green)
|
? (device.batteryLevel! < 20
|
||||||
|
? ColorsManager.red
|
||||||
|
: ColorsManager.green)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,56 +1,111 @@
|
|||||||
|
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:shared_preferences/shared_preferences.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/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/constants/strings_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.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);
|
||||||
|
}
|
||||||
|
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 =
|
||||||
|
@ -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,80 +1,129 @@
|
|||||||
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) {
|
||||||
builder: (context, state) {
|
if (state is HomeInitial) {
|
||||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
if (homeBloc.user!.hasAcceptedWebAgreement == false && !_dialogShown) {
|
||||||
return WebScaffold(
|
_dialogShown = true; // Set the flag to true to indicate the dialog is showing.
|
||||||
enableMenuSidebar: false,
|
Future.delayed(const Duration(seconds: 1), () {
|
||||||
appBarTitle: Row(
|
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) {
|
||||||
|
return WebScaffold(
|
||||||
|
enableMenuSidebar: false,
|
||||||
|
appBarTitle: Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
Assets.loginLogo,
|
||||||
|
width: 150,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
scaffoldBody: SizedBox(
|
||||||
|
height: size.height,
|
||||||
|
width: size.width,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
SvgPicture.asset(
|
Column(
|
||||||
Assets.loginLogo,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
width: 150,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: size.height * 0.1),
|
||||||
|
Text(
|
||||||
|
'ACCESS YOUR APPS',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.headlineLarge!
|
||||||
|
.copyWith(color: Colors.black, fontSize: 40),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: SizedBox(
|
||||||
|
height: size.height * 0.6,
|
||||||
|
width: size.width * 0.68,
|
||||||
|
child: GridView.builder(
|
||||||
|
itemCount: 3, // Change this count if needed.
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 3, // Adjust as needed.
|
||||||
|
crossAxisSpacing: 20.0,
|
||||||
|
mainAxisSpacing: 20.0,
|
||||||
|
childAspectRatio: 1.5,
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return HomeCard(
|
||||||
|
index: index,
|
||||||
|
active: homeBloc.homeItems[index].active!,
|
||||||
|
name: homeBloc.homeItems[index].title!,
|
||||||
|
img: homeBloc.homeItems[index].icon!,
|
||||||
|
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
scaffoldBody: SizedBox(
|
),
|
||||||
height: size.height,
|
);
|
||||||
width: size.width,
|
},
|
||||||
child: Column(
|
),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
);
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
SizedBox(height: size.height * 0.1),
|
|
||||||
Text(
|
|
||||||
'ACCESS YOUR APPS',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.headlineLarge!
|
|
||||||
.copyWith(color: Colors.black, fontSize: 40),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Expanded(
|
|
||||||
flex: 4,
|
|
||||||
child: SizedBox(
|
|
||||||
height: size.height * 0.6,
|
|
||||||
width: size.width * 0.68,
|
|
||||||
child: GridView.builder(
|
|
||||||
itemCount: 3, //8
|
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 4,
|
|
||||||
crossAxisSpacing: 20.0,
|
|
||||||
mainAxisSpacing: 20.0,
|
|
||||||
childAspectRatio: 1.5,
|
|
||||||
),
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return HomeCard(
|
|
||||||
index: index,
|
|
||||||
active: homeBloc.homeItems[index].active!,
|
|
||||||
name: homeBloc.homeItems[index].title!,
|
|
||||||
img: homeBloc.homeItems[index].icon!,
|
|
||||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,20 +335,26 @@ 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,
|
||||||
jobTitle: jobTitleController.text,
|
jobTitle: jobTitleController.text,
|
||||||
lastName: lastNameController.text,
|
lastName: lastNameController.text,
|
||||||
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,16 +384,20 @@ 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,
|
||||||
jobTitle: jobTitleController.text,
|
jobTitle: jobTitleController.text,
|
||||||
lastName: lastNameController.text,
|
lastName: lastNameController.text,
|
||||||
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) {
|
||||||
bloc.add(const CheckRoleStepStatus());
|
Future.delayed(const Duration(seconds: 1), () {
|
||||||
|
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,117 +46,120 @@ class BasicsView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Flexible(
|
||||||
width: MediaQuery.of(context).size.width * 0.18,
|
child: SizedBox(
|
||||||
height: MediaQuery.of(context).size.width * 0.08,
|
// width: MediaQuery.of(context).size.width * 0.18,
|
||||||
child: Column(
|
height: MediaQuery.of(context).size.width * 0.08,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
SizedBox(
|
children: [
|
||||||
child: Row(
|
SizedBox(
|
||||||
children: [
|
child: Row(
|
||||||
const Text(
|
children: [
|
||||||
" * ",
|
const Text(
|
||||||
style: TextStyle(
|
" * ",
|
||||||
color: ColorsManager.red,
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w900,
|
color: ColorsManager.red,
|
||||||
fontSize: 15,
|
fontWeight: FontWeight.w900,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Text(
|
||||||
Text(
|
'First Name',
|
||||||
'First Name',
|
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
fontSize: 13,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: TextFormField(
|
|
||||||
style:
|
|
||||||
const TextStyle(color: ColorsManager.blackColor),
|
|
||||||
// onChanged: (value) {
|
|
||||||
// Future.delayed(const Duration(milliseconds: 200),
|
|
||||||
// () {
|
|
||||||
// _blocRole.add(const ValidateBasicsStep());
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
controller: _blocRole.firstNameController,
|
|
||||||
decoration: inputTextFormDeco(
|
|
||||||
hintText: "Enter first name",
|
|
||||||
).copyWith(
|
|
||||||
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
fontSize: 12,
|
|
||||||
color: ColorsManager.textGray),
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Enter first name';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width * 0.18,
|
|
||||||
height: MediaQuery.of(context).size.width * 0.08,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
" * ",
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorsManager.red,
|
|
||||||
fontWeight: FontWeight.w900,
|
|
||||||
fontSize: 15,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text('Last Name',
|
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
)),
|
),
|
||||||
],
|
),
|
||||||
)),
|
],
|
||||||
Padding(
|
)),
|
||||||
padding: const EdgeInsets.all(8.0),
|
Padding(
|
||||||
child: TextFormField(
|
padding: const EdgeInsets.all(8.0),
|
||||||
// onChanged: (value) {
|
child: TextFormField(
|
||||||
// Future.delayed(const Duration(milliseconds: 200),
|
style: const TextStyle(
|
||||||
// () {
|
color: ColorsManager.blackColor),
|
||||||
// _blocRole.add(ValidateBasicsStep());
|
// onChanged: (value) {
|
||||||
// });
|
// Future.delayed(const Duration(milliseconds: 200),
|
||||||
// },
|
// () {
|
||||||
controller: _blocRole.lastNameController,
|
// _blocRole.add(const ValidateBasicsStep());
|
||||||
style: const TextStyle(color: Colors.black),
|
// });
|
||||||
decoration:
|
// },
|
||||||
inputTextFormDeco(hintText: "Enter last name")
|
controller: _blocRole.firstNameController,
|
||||||
.copyWith(
|
decoration: inputTextFormDeco(
|
||||||
hintStyle: context
|
hintText: "Enter first name",
|
||||||
.textTheme.bodyMedium
|
).copyWith(
|
||||||
?.copyWith(
|
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: ColorsManager.textGray)),
|
color: ColorsManager.textGray),
|
||||||
validator: (value) {
|
),
|
||||||
if (value == null || value.isEmpty) {
|
validator: (value) {
|
||||||
return 'Enter last name';
|
if (value == null || value.isEmpty) {
|
||||||
}
|
return 'Enter first name';
|
||||||
return null;
|
}
|
||||||
},
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Flexible(
|
||||||
|
child: SizedBox(
|
||||||
|
// width: MediaQuery.of(context).size.width * 0.18,
|
||||||
|
height: MediaQuery.of(context).size.width * 0.08,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
" * ",
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorsManager.red,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('Last Name',
|
||||||
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 13,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: TextFormField(
|
||||||
|
// onChanged: (value) {
|
||||||
|
// Future.delayed(const Duration(milliseconds: 200),
|
||||||
|
// () {
|
||||||
|
// _blocRole.add(ValidateBasicsStep());
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
controller: _blocRole.lastNameController,
|
||||||
|
style: const TextStyle(color: Colors.black),
|
||||||
|
decoration:
|
||||||
|
inputTextFormDeco(hintText: "Enter last name")
|
||||||
|
.copyWith(
|
||||||
|
hintStyle: context.textTheme.bodyMedium
|
||||||
|
?.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 12,
|
||||||
|
color: ColorsManager.textGray)),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return 'Enter last name';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -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,256 +1,59 @@
|
|||||||
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;
|
child: Container(
|
||||||
} else if (index == 9) {
|
width: width,
|
||||||
return screenWidth * 0.1;
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
}
|
decoration: const BoxDecoration(
|
||||||
return screenWidth * 0.09;
|
border: Border(right: BorderSide(color: ColorsManager.boxDivider)),
|
||||||
});
|
),
|
||||||
setState(() {});
|
child: Row(
|
||||||
}
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
return SingleChildScrollView(
|
|
||||||
clipBehavior: Clip.none,
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
child: Container(
|
|
||||||
decoration: containerDecoration.copyWith(
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(20))),
|
|
||||||
child: FittedBox(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Expanded(
|
||||||
width: totalWidth,
|
child: Text(
|
||||||
decoration: containerDecoration.copyWith(
|
title,
|
||||||
color: ColorsManager.circleRolesBackground,
|
maxLines: 2,
|
||||||
borderRadius: const BorderRadius.only(
|
overflow: TextOverflow.ellipsis,
|
||||||
topLeft: Radius.circular(15),
|
style: const TextStyle(
|
||||||
topRight: Radius.circular(15))),
|
fontWeight: FontWeight.w400,
|
||||||
child: Row(
|
fontSize: 13,
|
||||||
children: List.generate(widget.titles.length, (index) {
|
color: ColorsManager.grayColor,
|
||||||
return Row(
|
),
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
FittedBox(
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.only(left: 5, right: 5),
|
|
||||||
width: columnWidths[index],
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
child: Text(
|
|
||||||
widget.titles[index],
|
|
||||||
maxLines: 2,
|
|
||||||
style: const TextStyle(
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
fontSize: 13,
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (index != 1 &&
|
|
||||||
index != 9 &&
|
|
||||||
index != 8 &&
|
|
||||||
index != 5)
|
|
||||||
FittedBox(
|
|
||||||
child: IconButton(
|
|
||||||
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)
|
|
||||||
.clamp(150.0, 300.0);
|
|
||||||
totalWidth = columnWidths.reduce((a, b) => a + b);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: MouseRegion(
|
|
||||||
cursor: SystemMouseCursors.resizeColumn,
|
|
||||||
child: Container(
|
|
||||||
color: Colors.green,
|
|
||||||
child: Container(
|
|
||||||
color: ColorsManager.boxDivider,
|
|
||||||
width: 1,
|
|
||||||
height: 50,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
widget.rows.isEmpty
|
if (showFilter)
|
||||||
? SizedBox(
|
IconButton(
|
||||||
height: MediaQuery.of(context).size.height / 2,
|
icon: SvgPicture.asset(Assets.filterTableIcon),
|
||||||
child: Column(
|
onPressed: onFilter,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
padding: EdgeInsets.zero,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
constraints: const BoxConstraints(),
|
||||||
children: [
|
),
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(Assets.emptyTable),
|
|
||||||
const SizedBox(
|
|
||||||
height: 15,
|
|
||||||
),
|
|
||||||
const Text(
|
|
||||||
'No Users',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Center(
|
|
||||||
child: Container(
|
|
||||||
width: totalWidth,
|
|
||||||
decoration: containerDecoration.copyWith(
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(15),
|
|
||||||
bottomRight: Radius.circular(15))),
|
|
||||||
child: ListView.builder(
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
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: [
|
|
||||||
Container(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 5, top: 10, right: 5, bottom: 10),
|
|
||||||
child: Row(
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -258,3 +61,204 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _TableRow extends StatelessWidget {
|
||||||
|
final List<Widget> cells;
|
||||||
|
final List<double> columnWidths;
|
||||||
|
final bool isLast;
|
||||||
|
|
||||||
|
const _TableRow({
|
||||||
|
required this.cells,
|
||||||
|
required this.columnWidths,
|
||||||
|
required this.isLast,
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
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: [
|
||||||
|
SvgPicture.asset(Assets.emptyTable),
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
const Text(
|
||||||
|
'No Users',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: containerDecoration.copyWith(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(15),
|
||||||
|
bottomRight: Radius.circular(15),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
for (int rowIndex = 0; rowIndex < widget.rows.length; rowIndex++)
|
||||||
|
_TableRow(
|
||||||
|
cells: widget.rows[rowIndex],
|
||||||
|
columnWidths: columnWidths,
|
||||||
|
isLast: rowIndex == widget.rows.length - 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(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,7 +17,6 @@ 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';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class UsersPage extends StatelessWidget {
|
class UsersPage extends StatelessWidget {
|
||||||
UsersPage({super.key});
|
UsersPage({super.key});
|
||||||
|
|
||||||
@ -25,7 +24,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,9 +33,11 @@ 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"
|
||||||
? ColorsManager.red
|
? Colors.grey
|
||||||
: ColorsManager.spaceColor,
|
: title == "Delete"
|
||||||
|
? ColorsManager.red
|
||||||
|
: ColorsManager.spaceColor,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -108,7 +110,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 +131,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 +219,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 +227,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 +238,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 +268,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 +280,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 +324,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 +335,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 +350,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 +358,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 +375,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 +418,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 +435,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,28 +446,30 @@ class UsersPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
// actionButton(
|
user.isEnabled != false
|
||||||
// title: "Activity Log",
|
? actionButton(
|
||||||
// onTap: () {},
|
isActive: true,
|
||||||
// ),
|
title: "Edit",
|
||||||
actionButton(
|
onTap: () {
|
||||||
title: "Edit",
|
showDialog(
|
||||||
onTap: () {
|
context: context,
|
||||||
showDialog(
|
barrierDismissible: false,
|
||||||
context: context,
|
builder: (BuildContext context) {
|
||||||
barrierDismissible: false,
|
return EditUserDialog(
|
||||||
builder: (BuildContext context) {
|
userId: user.uuid);
|
||||||
return EditUserDialog(userId: user.uuid);
|
},
|
||||||
},
|
).then((v) {
|
||||||
).then((v) {
|
if (v != null) {
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
if (v != null) {
|
_blocRole.add(const GetUsers());
|
||||||
_blocRole.add(const GetUsers());
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
},
|
||||||
},
|
)
|
||||||
),
|
: actionButton(
|
||||||
|
title: "Edit",
|
||||||
|
),
|
||||||
actionButton(
|
actionButton(
|
||||||
title: "Delete",
|
title: "Delete",
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -487,9 +492,7 @@ 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 +519,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()) {
|
||||||
@ -57,8 +64,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,48 +161,57 @@ 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,
|
||||||
));
|
));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
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>();
|
||||||
emit(state.copyWith(
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
automations: automations,
|
List<String> spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
isLoading: false,
|
for (var spaceId in spacesList) {
|
||||||
));
|
automations.addAll(await SceneApi.getAutomation(spaceId));
|
||||||
} else {
|
}
|
||||||
emit(state.copyWith(
|
}
|
||||||
|
emit(state.copyWith(
|
||||||
|
automations: automations,
|
||||||
|
isLoading: false,
|
||||||
|
));
|
||||||
|
} catch (e) {
|
||||||
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
loadAutomationErrorMessage: 'Failed to load automations',
|
loadAutomationErrorMessage: 'Failed to load automations',
|
||||||
errorMessage: '',
|
errorMessage: '',
|
||||||
loadScenesErrorMessage: '',
|
loadScenesErrorMessage: '',
|
||||||
));
|
automations: automations));
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
emit(state.copyWith(
|
|
||||||
isLoading: false,
|
|
||||||
loadAutomationErrorMessage: 'Failed to load automations',
|
|
||||||
errorMessage: '',
|
|
||||||
loadScenesErrorMessage: '',
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,8 +294,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 +309,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,
|
||||||
@ -402,9 +421,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 +440,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,
|
||||||
@ -776,17 +797,21 @@ 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) {
|
||||||
@ -814,7 +839,19 @@ 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) {
|
||||||
@ -892,8 +929,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
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,
|
||||||
@ -1003,8 +1040,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(
|
||||||
@ -1021,8 +1061,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
|
|
||||||
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,
|
@ -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 {
|
||||||
@ -68,7 +68,7 @@ class CreateNewRoutineView extends StatelessWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
color: ColorsManager.dialogBlueTitle,
|
color: ColorsManager.dialogBlueTitle,
|
||||||
),
|
),
|
||||||
|
|
||||||
/// THEN Container
|
/// THEN Container
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Card(
|
child: Card(
|
@ -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]['uniqueCustomId']));
|
||||||
key: state.ifItems[index]
|
|
||||||
['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,
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user