Compare commits

..

15 Commits

Author SHA1 Message Date
3bc20a48c9 Merge pull request #117 from SyncrowIOT/Add-Booking-to-bottom-navigation-bar
[FE] Add Booking to bottom navigation bar
2025-07-23 14:30:01 +03:00
bae6a09a87 fix imports 2025-07-23 14:09:23 +03:00
6f0e83b95b fix UI depend on the new design 2025-07-23 14:08:57 +03:00
15b6d642ff add the icon to nave bar and remove from menu 2025-07-23 14:08:38 +03:00
99852464c7 Merge pull request #116 from SyncrowIOT/SP-1851-fe-change-the-routine-title-to-workflow-automation-in-the-web-and-to-automation-in-the-app
[FE] Change the routine title to "Workflow Automation" in the web and to "automation" in the app
2025-07-21 13:25:38 +03:00
4ac6077011 change all routine words into automation 2025-07-21 13:22:29 +03:00
d5321a9ca0 fix inncorrect parent in automation screen by removing Expanded 2025-07-21 13:21:02 +03:00
9d507f30eb Merge pull request #115 from SyncrowIOT/SP-349-fe-implement-consistent-name-validation-in-profile-section-same-as-sign-up
[FE] Implement Consistent Name Validation in Profile Section same as sign up
2025-07-21 10:16:50 +03:00
029e36ee3d Merge pull request #114 from SyncrowIOT/SP-1851-fe-change-the-routine-title-to-workflow-automation-in-the-web-and-to-automation-in-the-app
[FE] Change the routine title to "Workflow Automation" in the web and to "automation" in the app
2025-07-21 09:08:19 +03:00
dd55d5c082 add needed rules for the provided name (first nd last) 2025-07-21 09:04:44 +03:00
09dc8cc330 use uppercase 2025-07-20 14:34:19 +03:00
76da7debfd Merge pull request #113 from SyncrowIOT/SP-519-delete-account
Delete account
2025-07-20 13:55:46 +03:00
f7245e5de9 change th e word Routine to automation 2025-07-15 11:06:49 +03:00
fe472f0ca0 Merge pull request #112 from SyncrowIOT/SP-368-clarification-on-default-value-for-start-date-in-door-lock-online-tile-limited-password-repeat-section
Clarification on Default Value for Start Date in Door Lock Online Tile Limited Password repeat section
2025-07-02 09:12:48 +03:00
d9b68a11e5 fix the initial value on start date and fix logic that prevent user from select old date (befor now) 2025-07-01 14:09:14 +03:00
18 changed files with 332 additions and 230 deletions

View File

@ -0,0 +1,10 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_11681_2046)">
<path d="M20.615 14.4212L18.9717 5.10949C18.62 3.11866 16.89 1.66699 14.8684 1.66699H6.46502C3.58336 1.66699 2.57836 3.87949 2.36169 5.10949L0.726691 14.3703C0.625024 14.9487 0.646691 15.5512 0.848357 16.102C1.35502 17.4895 2.62252 18.3337 4.00086 18.3337C4.00086 18.3337 4.93586 18.3287 4.98752 18.3187C5.35502 18.2495 5.60836 17.9462 5.64919 17.5928C5.14919 16.9095 4.77586 16.122 4.61086 15.2453L3.61836 9.97616C3.47252 9.20199 3.47586 8.40866 3.62752 7.63532C3.86252 6.43866 4.20669 4.74033 4.29836 4.58199L6.24752 14.937C6.61836 16.9062 8.33836 18.3328 10.3425 18.3328H17.2109C17.9684 18.3328 18.7284 18.1287 19.3317 17.6695C20.3575 16.8895 20.83 15.6403 20.615 14.4212ZM8.16669 6.66699C8.16669 6.20699 8.54002 5.83366 9.00002 5.83366H14.8334C15.2934 5.83366 15.6667 6.20699 15.6667 6.66699C15.6667 7.12699 15.2934 7.50033 14.8334 7.50033H9.00002C8.54002 7.50033 8.16669 7.12699 8.16669 6.66699ZM8.77586 10.0003C8.77586 9.54033 9.14919 9.16699 9.60919 9.16699H15.4425C15.9025 9.16699 16.2759 9.54033 16.2759 10.0003C16.2759 10.4603 15.9025 10.8337 15.4425 10.8337H9.60919C9.14919 10.8337 8.77586 10.4603 8.77586 10.0003ZM16.0834 14.167H10.25C9.79002 14.167 9.41669 13.7945 9.41669 13.3337C9.41669 12.8728 9.79002 12.5003 10.25 12.5003H16.0834C16.5434 12.5003 16.9167 12.8728 16.9167 13.3337C16.9167 13.7945 16.5434 14.167 16.0834 14.167Z" fill="#999999"/>
</g>
<defs>
<clipPath id="clip0_11681_2046">
<rect width="20" height="20" fill="white" transform="translate(0.666687)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -12,6 +12,7 @@ import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/features/booking_system/presentation/screens/booking_system_page.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
@ -32,6 +33,7 @@ import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
part 'home_state.dart';
class HomeCubit extends Cubit<HomeState> {
@ -479,7 +481,7 @@ class HomeCubit extends Cubit<HomeState> {
// onPressed: () {},
// ),
],
'Routine': [
'Automation': [
// IconButton(
// icon: Image.asset(
// Assets.assetsIconsFilter,
@ -538,6 +540,7 @@ class HomeCubit extends Cubit<HomeState> {
// onPressed: () {},
// ),
],
'Booking': [],
'Menu': [
// IconButton(
// icon: SvgPicture.asset(
@ -553,7 +556,19 @@ class HomeCubit extends Cubit<HomeState> {
static Map<String, Widget?> appBarLeading = {
// 'Dashboard': const AppBarHomeDropdown(),
'Devices': const AppBarHomeDropdown(),
'Routine': const AppBarHomeDropdown(),
'Automation': const AppBarHomeDropdown(),
'Booking': Padding(
padding: const EdgeInsets.only(left: 15),
child: Text(
'Booking',
style: TextStyle(
color: ColorsManager.textPrimaryColor,
fontSize: 26,
fontFamily: FontsManager.fontFamily,
fontWeight: FontWeight.w700,
),
),
),
'Menu': Padding(
padding: const EdgeInsets.only(left: 15),
child: Image.asset(
@ -569,7 +584,9 @@ class HomeCubit extends Cubit<HomeState> {
// defaultBottomNavBarItem(icon: Assets.assetsIconsDashboard, label: 'Dashboard'),
// defaultBottomNavBarItem(icon: Assets.assetsIconslayout, label: 'Layout'),
defaultBottomNavBarItem(icon: Assets.assetsIconsDevices, label: 'Devices'),
defaultBottomNavBarItem(icon: Assets.assetsIconsRoutines, label: 'Routine'),
defaultBottomNavBarItem(
icon: Assets.assetsIconsRoutines, label: 'Automation'),
defaultBottomNavBarItem(icon: Assets.bookingIcon, label: 'Booking'),
defaultBottomNavBarItem(icon: Assets.assetsIconsMenu, label: 'Menu'),
];
@ -581,6 +598,7 @@ class HomeCubit extends Cubit<HomeState> {
child: const DevicesViewBody(),
),
const RoutinesView(),
const BookingSystemPage(),
const MenuView(),
];
@ -616,7 +634,6 @@ BottomNavigationBarItem defaultBottomNavBarItem(
);
}
// class PermissionUtils {
// // Check if the "VIEW" permission exists in "MANAGE_SUBSPACE"
// static bool hasViewPermission(List<dynamic> permissions) {

View File

@ -3,9 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/booking_system/data/booking_dummy_source.dart';
import 'package:syncrow_app/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_bloc.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import '../blocs/past_bookings_bloc/past_bookings_bloc.dart';
import '../widgets/booking_appbar_widget.dart';
import '../widgets/current_balance_widget.dart';
import '../widgets/past_booking_widget.dart';
import '../widgets/upcoming_bookings_widget.dart';
@ -26,41 +24,35 @@ class BookingSystemPage extends StatelessWidget {
..add(GetPastBookingsEvent()),
)
],
child: DefaultScaffold(
appBar: BookingAppBar(),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 20,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 2,
child: CurrentBalanceWidget(
userBalance: HomeCubit.user!.points == null
? '0'
: HomeCubit.user!.points.toString(),
),
Expanded(
flex: 2,
child: CurrentBalanceWidget(
userBalance: HomeCubit.user!.points == null
? '0'
: HomeCubit.user!.points.toString(),
),
),
SizedBox(
height: 20,
),
Expanded(
flex: 8,
child: Column(
children: [
UpcomingBookingsWidget(),
SizedBox(
height: 10,
),
PastBookingsWidget(),
],
),
SizedBox(
height: 20,
),
Expanded(
flex: 8,
child: Column(
children: [
UpcomingBookingsWidget(),
SizedBox(
height: 10,
),
PastBookingsWidget(),
],
),
)
],
),
)
],
),
));
}

View File

@ -10,10 +10,7 @@ class BookingAppBar extends StatelessWidget implements PreferredSizeWidget {
return AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
leading: IconButton(
onPressed: () => Navigator.pop(context),
icon: Icon(Icons.arrow_back_ios_new)),
title: Text(
leading: Text(
'Booking',
style: TextStyle(
color: ColorsManager.blueColor1,

View File

@ -39,7 +39,7 @@ class PastBookingsWidget extends StatelessWidget {
);
} else if (state is PastBookingLoadedState) {
return SizedBox(
height: deviceHeight(context) * 0.3,
height: deviceHeight(context) * 0.22,
child: state.pastBookings.isEmpty
? Text('You Dont Have past Bookings')
: ListView.separated(

View File

@ -354,6 +354,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
Future<void> selectTimeOnlinePassword(
SelectTimeOnlinePasswordEvent event, Emitter<SmartDoorState> emit) async {
effectiveTimeTimeStamp ??= DateTime.now().millisecondsSinceEpoch ~/ 1000;
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
context: event.context,
@ -398,7 +399,13 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
selectedDateTime.minute,
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
final currentTimestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
if (event.isEffective) {
if (selectedTimestamp < currentTimestamp) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
return;
}
if (expirationTimeTimeStamp != null &&
selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(

View File

@ -11,6 +11,9 @@ class NameTimeWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
DateTime now = DateTime.now();
DateTime cleaned =
DateTime(now.year, now.month, now.day, now.hour, now.minute);
return DefaultContainer(
padding: const EdgeInsets.all(20),
child: Column(
@ -59,19 +62,22 @@ class NameTimeWidget extends StatelessWidget {
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeOnlinePasswordEvent(context: context, isEffective: true));
BlocProvider.of<SmartDoorBloc>(context).add(
SelectTimeOnlinePasswordEvent(
context: context, isEffective: true));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).effectiveTime,
style: TextStyle(fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context).effectiveTime ==
BlocProvider.of<SmartDoorBloc>(context)
.effectiveTime ==
'Select Time'
? ColorsManager.textGray
: null),
? cleaned.toString()
: BlocProvider.of<SmartDoorBloc>(context)
.effectiveTime,
style: TextStyle(fontSize: 14),
),
)),
],),
],
),
),
const Divider(
color: ColorsManager.graysColor,
@ -96,10 +102,13 @@ class NameTimeWidget extends StatelessWidget {
context: context, isEffective: false));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).expirationTime,
BlocProvider.of<SmartDoorBloc>(context)
.expirationTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context).expirationTime == 'Select Time'
color: BlocProvider.of<SmartDoorBloc>(context)
.expirationTime ==
'Select Time'
? ColorsManager.textGray
: null),
),

View File

@ -18,7 +18,8 @@ import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
final String? deviceId;
final String? type;
const CreateOfflineTimeLimitPasswordPage({super.key, this.deviceId, this.type});
const CreateOfflineTimeLimitPasswordPage(
{super.key, this.deviceId, this.type});
@override
Widget build(BuildContext context) {
bool isRepeat = false;
@ -28,9 +29,7 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
CustomSnackBar.displaySnackBar(
state.errorMessage
);
CustomSnackBar.displaySnackBar(state.errorMessage);
}
if (state is IsRepeatState) {
isRepeat = state.repeat;
@ -39,6 +38,10 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
generated = state.generated;
}
}, builder: (context, state) {
DateTime now = DateTime.now();
DateTime cleaned =
DateTime(now.year, now.month, now.day, now.hour, now.minute);
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
appBar: AppBar(
@ -85,46 +88,56 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: smartDoorBloc.passwordController.text.isEmpty ?
List.generate(10, (index) {
return const Padding(
padding: EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 15),
child: Icon(
Icons.circle,
size: 20.0,
color: Colors.black,
),
);
}) : [
Expanded(
child: Row(
children: [
children: smartDoorBloc
.passwordController.text.isEmpty
? List.generate(10, (index) {
return const Padding(
padding: EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 15),
child: Icon(
Icons.circle,
size: 20.0,
color: Colors.black,
),
);
})
: [
Expanded(
child: BodyLarge(
style: const TextStyle(
color: ColorsManager.primaryColor,
fontWeight: FontWeight.bold,
letterSpacing: 8.0,
fontSize: 25,
wordSpacing: 2),
textAlign: TextAlign.center,
text: smartDoorBloc.passwordController.text,
fontSize: 25,
child: Row(
children: [
Expanded(
child: BodyLarge(
style: const TextStyle(
color: ColorsManager
.primaryColor,
fontWeight:
FontWeight.bold,
letterSpacing: 8.0,
fontSize: 25,
wordSpacing: 2),
textAlign:
TextAlign.center,
text: smartDoorBloc
.passwordController
.text,
fontSize: 25,
),
),
IconButton(
onPressed: () async {
await Clipboard.setData(
ClipboardData(
text: smartDoorBloc
.passwordController
.text));
},
icon: const Icon(
Icons.copy)),
],
),
),
IconButton(
onPressed: () async {
await Clipboard.setData(
ClipboardData(text: smartDoorBloc.passwordController.text)
);
},
icon: const Icon(Icons.copy)),
],
),
),
],
)),
const SizedBox(
width: 10,
@ -135,91 +148,142 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: const BodyMedium(
text: 'Password Name',
fontWeight: FontWeight.normal,
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 2.6,
child: TextFormField(
controller: BlocProvider.of<SmartDoorBloc>(context).passwordNameController,
decoration:
const InputDecoration(
hintText: 'Enter The Name',
hintStyle: TextStyle(
fontSize: 14,
color: ColorsManager.textGray)
),
)),
],
),
Column(
children: [
const Divider(color: ColorsManager.graysColor,),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Effective Time',
fontWeight: FontWeight.normal,
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
padding:
const EdgeInsets.all(10.0),
child: const BodyMedium(
text: 'Password Name',
fontWeight: FontWeight.normal,
),
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeEvent(context: context, isEffective: true));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).effectiveTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context).effectiveTime ==
'Select Time' ? ColorsManager.textGray : null),
),
)),],
),
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Expiration Time',
fontWeight: FontWeight.normal,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeEvent(
context: context,
isEffective: false));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).expirationTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context)
.expirationTime == 'Select Time' ? ColorsManager
.textGray : null),
SizedBox(
width: MediaQuery.of(context)
.size
.width /
2.6,
child: TextFormField(
controller: BlocProvider.of<
SmartDoorBloc>(context)
.passwordNameController,
decoration:
const InputDecoration(
hintText:
'Enter The Name',
hintStyle: TextStyle(
fontSize: 14,
color: ColorsManager
.textGray)),
)),
],
),
Column(
children: [
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Effective Time',
fontWeight:
FontWeight.normal,
),
),
SizedBox(
width:
MediaQuery.of(context)
.size
.width /
3.5,
child: InkWell(
onTap: () {
BlocProvider.of<
SmartDoorBloc>(
context)
.add(
SelectTimeEvent(
context:
context,
isEffective:
true));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(
context)
.effectiveTime ==
'Select Time'
? cleaned.toString()
: BlocProvider.of<
SmartDoorBloc>(
context)
.effectiveTime,
style: TextStyle(
fontSize: 14,
),
),
)),
],
),
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Expiration Time',
fontWeight:
FontWeight.normal,
),
),
SizedBox(
width: MediaQuery.of(context)
.size
.width /
3.5,
child: InkWell(
onTap: () {
BlocProvider.of<
SmartDoorBloc>(
context)
.add(SelectTimeEvent(
context: context,
isEffective:
false));
},
child: Text(
BlocProvider.of<
SmartDoorBloc>(
context)
.expirationTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<
SmartDoorBloc>(
context)
.expirationTime ==
'Select Time'
? ColorsManager
.textGray
: null),
),
),
),
@ -238,7 +302,8 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
),
const BodyMedium(
textAlign: TextAlign.center,
text: 'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.',
text:
'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
@ -256,10 +321,13 @@ class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
backgroundColor: ColorsManager.primaryColor,
onPressed: () async {
if (generated == false) {
smartDoorBloc.add(GenerateAndSavePasswordTimeLimitEvent(context: context));
smartDoorBloc.add(
GenerateAndSavePasswordTimeLimitEvent(
context: context));
} else {
if(smartDoorBloc.passwordNameController.text.isNotEmpty){
smartDoorBloc.add(RenamePasswordEvent());
if (smartDoorBloc
.passwordNameController.text.isNotEmpty) {
smartDoorBloc.add(RenamePasswordEvent());
}
Navigator.of(context).pop(true);
}

View File

@ -45,18 +45,6 @@ class MenuCubit extends Cubit<MenuState> {
}
List<Map<String, Object>> menuSections = [
//Booking System
{
'title': 'Booking System',
'color': const Color(0xFF8AB9FF),
'buttons': [
{
'title': 'Booking',
'Icon': Assets.assetsIconsMenuBookingSystem,
'page': BookingSystemPage()
},
],
},
//Home Management
{
'title': 'Home Management',

View File

@ -262,6 +262,17 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
if (parts.any((part) => part.length < 2 || part.length > 30)) {
return 'Full name parts must be between 2 and 30 characters long';
}
if (RegExp(r"\s{2,}").hasMatch(value)) {
return 'Only one space is allowed between first and last names';
}
// Check for leading or trailing spaces
if (value != value.trim()) {
return 'No leading or trailing spaces allowed';
}
// Check if only alphabetic characters and one space are used
if (!RegExp(r'^[A-Za-z]+(?: [A-Za-z]+)?$').hasMatch(value)) {
return 'Only alphabetic characters and a single space are allowed';
}
return null;
}

View File

@ -27,12 +27,15 @@ class RoutinesView extends StatelessWidget {
builder: (context, state) {
final selectedSpace = HomeCubit.getInstance().selectedSpace;
if (state is DeleteSceneSuccess) {
if (state.success) _loadScenesAndAutomations(context, selectedSpace);
if (state.success)
_loadScenesAndAutomations(context, selectedSpace);
}
if (state is CreateSceneWithTasks) {
if (state.success) {
_loadScenesAndAutomations(context, selectedSpace);
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent());
context
.read<SmartSceneSelectBloc>()
.add(const SmartSceneClearEvent());
}
}
return BlocListener<SceneBloc, SceneState>(
@ -72,30 +75,28 @@ class RoutinesView extends StatelessWidget {
data: Theme.of(context).copyWith(
dividerColor: Colors.transparent,
),
child: Expanded(
child: ListView(
children: [
RoutinesExpansionTile(
title: 'Tap to run routines',
emptyRoutinesMessage:
'No scenes have been added yet',
routines: state.scenes,
loadingStates: state.loadingStates,
loadingSceneId: state.loadingSceneId,
disablePlayButton: false,
),
RoutinesExpansionTile(
title: 'Automation',
emptyRoutinesMessage:
'No automations have been added yet',
routines: state.automationList,
loadingStates: state.loadingStates,
loadingSceneId: state.loadingSceneId,
disablePlayButton: true,
),
const SizedBox(height: 15),
],
),
child: ListView(
children: [
RoutinesExpansionTile(
title: 'Tap to run automations',
emptyRoutinesMessage:
'No scenes have been added yet',
routines: state.scenes,
loadingStates: state.loadingStates,
loadingSceneId: state.loadingSceneId,
disablePlayButton: false,
),
RoutinesExpansionTile(
title: 'Automation',
emptyRoutinesMessage:
'No automations have been added yet',
routines: state.automationList,
loadingStates: state.loadingStates,
loadingSceneId: state.loadingSceneId,
disablePlayButton: true,
),
const SizedBox(height: 15),
],
),
);
}
@ -111,7 +112,8 @@ class RoutinesView extends StatelessWidget {
);
}
void _loadScenesAndAutomations(BuildContext context, SpaceModel? selectedSpace) {
void _loadScenesAndAutomations(
BuildContext context, SpaceModel? selectedSpace) {
context.read<SceneBloc>()
..add(LoadScenes(selectedSpace!.id, selectedSpace, showInDevice: false))
..add(LoadAutomation(selectedSpace.id, selectedSpace.community.uuid));

View File

@ -100,7 +100,7 @@ class SceneView extends StatelessWidget {
initiallyExpanded: true,
iconColor: ColorsManager.grayColor,
title: const BodyMedium(
text: 'Tap to run routines',
text: 'Tap to run automations',
),
children: [
if (scenes.isNotEmpty)

View File

@ -23,7 +23,7 @@ class DeleteRoutineDialog extends StatelessWidget {
height: 10,
),
const BodyLarge(
text: 'Delete Routine',
text: 'Delete Automation',
fontWeight: FontWeight.w700,
fontColor: ColorsManager.red,
fontSize: 16,
@ -39,7 +39,7 @@ class DeleteRoutineDialog extends StatelessWidget {
child: Column(
children: [
Center(child: const Text('Are you sure you want to ')),
Center(child: const Text('delete the routine?'))
Center(child: const Text('delete the automation?'))
],
),
),

View File

@ -52,7 +52,7 @@ class DeleteRoutineButton extends StatelessWidget {
},
child: const Center(
child: Text(
'Remove Routine',
'Remove Automation',
style: TextStyle(color: ColorsManager.red),
))
// : SceneListTile(

View File

@ -9,7 +9,7 @@ class EmptyDevicesWidget extends StatelessWidget {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 48),
child: Text(
"No routines.\nEnable 'Show on Home Screen' to add routines",
"No automations.\nEnable 'Show on Home Screen' to add automations",
textAlign: TextAlign.center,
style: TextStyle(
color: ColorsManager.grayColor,

View File

@ -23,7 +23,7 @@ class EmptyRoutinesWidget extends StatelessWidget {
),
),
BodyMedium(
text: 'No Routines yet',
text: 'No automations yet',
fontColor: ColorsManager.textGray,
),
],

View File

@ -1129,6 +1129,7 @@ class Assets {
static const String verificationIcon = "assets/icons/verification_icon.svg";
static const String deleteAccountIcon='assets/icons/delete_account_icon.svg';
static const String bookingIcon='assets/icons/booking_icon.svg';
static const String passwordUnvisibility =
"assets/icons/password_unvisibility.svg";
static const String passwordVisibility =

View File

@ -4,8 +4,8 @@ class StringsManager {
static const String dashboard = 'Dashboard';
static const String devices = 'Devices';
static const String routine = 'Routines';
static const String tapToRunRoutine = 'Tap to run routine';
static const String routine = 'Automation';
static const String tapToRunRoutine = 'Tap to run automation';
static const String wizard = 'Wizard';
static const String active = 'Active';
static const String current = 'Current';
@ -39,6 +39,6 @@ class StringsManager {
'Example: when an unusual activity is detected.';
static const String functions = "Functions";
static const String firstLaunch = "firstLaunch";
static const String deleteScene = 'Remove Routine';
static const String deleteScene = 'Remove Automation';
static const String deleteAutomation = 'Delete Automation';
}